]> rtime.felk.cvut.cz Git - l4.git/commitdiff
update
authorl4check <l4check@d050ee49-bd90-4346-b210-929a50b99cfc>
Thu, 11 Aug 2011 21:18:25 +0000 (21:18 +0000)
committerl4check <l4check@d050ee49-bd90-4346-b210-929a50b99cfc>
Thu, 11 Aug 2011 21:18:25 +0000 (21:18 +0000)
git-svn-id: http://svn.tudos.org/repos/oc/tudos/trunk@38 d050ee49-bd90-4346-b210-929a50b99cfc

459 files changed:
kernel/fiasco/src/Kconfig
kernel/fiasco/src/Makeconf.arm
kernel/fiasco/src/Modules.arm
kernel/fiasco/src/jdb/jdb_kobject.cpp
kernel/fiasco/src/jdb/jdb_log.cpp
kernel/fiasco/src/kern/arm/bootstrap.cpp
kernel/fiasco/src/kern/arm/bsp/realview/Kconfig
kernel/fiasco/src/kern/arm/bsp/realview/Modules
kernel/fiasco/src/kern/arm/bsp/realview/mem_layout-arm-realview.cpp
kernel/fiasco/src/kern/arm/bsp/realview/outer_cache-arm-realview.cpp
kernel/fiasco/src/kern/arm/bsp/tegra2/Kconfig
kernel/fiasco/src/kern/arm/bsp/tegra2/Modules
kernel/fiasco/src/kern/arm/bsp/tegra2/mem_layout-arm-tegra2.cpp
kernel/fiasco/src/kern/arm/bsp/tegra2/outer_cache-arm-tegra2.cpp [new file with mode: 0644]
kernel/fiasco/src/kern/arm/bsp/tegra2/pic-arm-tegra2.cpp
kernel/fiasco/src/kern/arm/config-arm.cpp
kernel/fiasco/src/kern/arm/context-arm.cpp
kernel/fiasco/src/kern/arm/fpu-arm.cpp
kernel/fiasco/src/kern/arm/ivt.S
kernel/fiasco/src/kern/arm/mem_space-arm.cpp
kernel/fiasco/src/kern/arm/outer_cache-l2cxx0.cpp [new file with mode: 0644]
kernel/fiasco/src/kern/arm/pagetable-arch.cpp
kernel/fiasco/src/kern/arm/sys_call_page-arm.cpp
kernel/fiasco/src/kern/arm/thread-arm.cpp
kernel/fiasco/src/kern/arm/tramp-mp.S
kernel/fiasco/src/kern/config.cpp
kernel/fiasco/src/kern/cpu_mask.cpp
kernel/fiasco/src/kern/dirq_io_apic.cpp
kernel/fiasco/src/kern/fpu.cpp
kernel/fiasco/src/kern/ia32/32/main-ia32-32.cpp
kernel/fiasco/src/kern/ia32/64/main-ia32-64.cpp
kernel/fiasco/src/kern/ia32/main-ia32.cpp
kernel/fiasco/src/kern/io_apic.cpp
kernel/fiasco/src/kern/mem_space_sigma0.cpp
kernel/fiasco/src/kern/ppc32/config-ppc32.cpp
kernel/fiasco/src/kern/tb_entry_output.cpp
kernel/fiasco/src/kern/thread-ipc.cpp
kernel/fiasco/src/kern/thread_object.cpp
kernel/fiasco/src/lib/libk/bitmap.cpp
kernel/fiasco/src/templates/globalconfig.out.arm-a9-mp-1
kernel/fiasco/src/templates/globalconfig.out.arm-a9-mp-2
kernel/fiasco/src/templates/globalconfig.out.arm-rv-1
kernel/fiasco/src/templates/globalconfig.out.arm-rv-2
kernel/fiasco/src/templates/globalconfig.out.arm-rv-3
kernel/fiasco/src/templates/globalconfig.out.arm-rv-4-noinl
kernel/fiasco/src/templates/globalconfig.out.arm-t2
kernel/fiasco/src/templates/globalconfig.out.arm-v6
kernel/fiasco/src/templates/globalconfig.out.arm-v6-mp-eb
kernel/fiasco/src/templates/globalconfig.out.arm-v6-mp-pb
kernel/fiasco/src/templates/globalconfig.out.arm-v7
kernel/fiasco/tool/kconfig/Makefile
kernel/fiasco/tool/kconfig/README
kernel/fiasco/tool/kconfig/scripts/Kbuild.include
kernel/fiasco/tool/kconfig/scripts/Makefile
kernel/fiasco/tool/kconfig/scripts/Makefile.build
kernel/fiasco/tool/kconfig/scripts/Makefile.headersinst
kernel/fiasco/tool/kconfig/scripts/Makefile.lib
kernel/fiasco/tool/kconfig/scripts/basic/Makefile
kernel/fiasco/tool/kconfig/scripts/kconfig/Makefile
kernel/fiasco/tool/kconfig/scripts/kconfig/confdata.c
kernel/fiasco/tool/kconfig/scripts/kconfig/expr.h
kernel/fiasco/tool/kconfig/scripts/kconfig/gconf.c
kernel/fiasco/tool/kconfig/scripts/kconfig/lex.zconf.c_shipped
kernel/fiasco/tool/kconfig/scripts/kconfig/nconf.c
kernel/fiasco/tool/kconfig/scripts/kconfig/qconf.cc
kernel/fiasco/tool/kconfig/scripts/kconfig/zconf.l
l4/Makefile
l4/mk/Kconfig
l4/mk/Makeconf
l4/mk/aliases.d/10-stdlibs
l4/mk/defconfig/config.ppc32
l4/mk/defconfig/config.sparc
l4/mk/export_defs.inc
l4/mk/modes.inc
l4/pkg/ankh/examples/morpork/main.cc
l4/pkg/ankh/examples/pingpong/ping.cc
l4/pkg/ankh/lib/client-c/lib.cc
l4/pkg/ankh/lib/lwip/WTF
l4/pkg/ankh/lib/lwip/lib/Makefile
l4/pkg/ankh/lib/lwip/lib/arch/ankh_if.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/api_lib.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/api_msg.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/err.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/netbuf.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/netdb.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/sockets.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/api/tcpip.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/dhcp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/dns.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/inet_chksum.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/init.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/autoip.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/icmp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/igmp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4_addr.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip_frag.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/dhcp6.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ethip6.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/icmp6.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/inet6.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ip6.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ip6_addr.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ip6_frag.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/mld6.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/nd6.c [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/mem.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/memp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/netif.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/pbuf.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/raw.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/snmp/mib2.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/snmp/msg_in.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/stats.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/tcp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/tcp_in.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/tcp_out.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/timers.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/core/udp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/autoip.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/icmp.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/inet.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4_addr.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip_frag.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/dhcp6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ethip6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/icmp6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/inet6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_addr.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_frag.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/mld6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/nd6.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/api.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/api_msg.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/arch.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/debug.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/dhcp.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/dns.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/err.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/inet_chksum.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/init.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip_addr.h [new file with mode: 0644]
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/mem.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/memp_std.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/netbuf.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/netdb.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/netif.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/opt.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/pbuf.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/raw.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/snmp_asn1.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/sockets.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/stats.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/tcp.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/tcp_impl.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/tcpip.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/timers.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/udp.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/netif/etharp.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/include/netif/ppp_oe.h
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/etharp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ethernetif.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/auth.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/chap.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/fsm.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/ipcp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/lcp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/pap.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/ppp/ppp.c
l4/pkg/ankh/lib/lwip/lib/contrib/src/netif/slipif.c
l4/pkg/ankh/server/src/device.cc
l4/pkg/ankh/server/src/main.cc
l4/pkg/ankh/server/src/session
l4/pkg/bootstrap/server/src/ARCH-sparc/bootstrap.ld.in
l4/pkg/bootstrap/server/src/ARCH-sparc/crt0.S
l4/pkg/bootstrap/server/src/Make.rules
l4/pkg/bootstrap/server/src/libc_support+.cc
l4/pkg/bootstrap/server/src/platform/imx.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/integrator.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/kirkwood.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/leon3.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/mpc5200.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/om.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/omap.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/pxa.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/rv.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/sa1000.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/tegra2.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/platform/x86_pc.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/startup.cc
l4/pkg/cxx/lib/base/include/Makefile
l4/pkg/cxx/lib/base/include/std_exc_io [new file with mode: 0644]
l4/pkg/cxx/lib/ipc/include/ipc_stream
l4/pkg/cxx/lib/tl/include/avl_tree
l4/pkg/dde-libinput/src/dde26_input.h
l4/pkg/dde-libinput/src/libinput.c
l4/pkg/dde/ddekit/src/memory.cc
l4/pkg/dope/lib/dope/common/main.c
l4/pkg/dope/lib/dope/l4/Makefile
l4/pkg/dope/lib/dope/l4/func.cc
l4/pkg/dope/lib/dope/l4/init.c
l4/pkg/dope/server/l4/server.cc
l4/pkg/drivers-frst/uart/include/uart_leon3.h [new file with mode: 0644]
l4/pkg/drivers-frst/uart/src/Makefile
l4/pkg/drivers-frst/uart/src/uart_leon3.cc [new file with mode: 0644]
l4/pkg/examples/clntsrv/Makefile
l4/pkg/examples/clntsrv/client.cc
l4/pkg/examples/clntsrv/server.cc
l4/pkg/examples/libs/l4re/c++/shared_ds/ds_srv.cc
l4/pkg/examples/libs/l4re/streammap/client.cc
l4/pkg/examples/libs/l4re/streammap/server.cc
l4/pkg/examples/sys/vcpu/Makefile
l4/pkg/fb-drv/server/src/fb.h
l4/pkg/fb-drv/server/src/main.cc
l4/pkg/fbterminal/server/src/main.cc
l4/pkg/fuxfprov/server/src/Makefile
l4/pkg/fuxfprov/server/src/main.cc
l4/pkg/input/lib/include/internal.h
l4/pkg/input/lib/src-dummy/main.c
l4/pkg/input/lib/src/init.c
l4/pkg/input/lib/src/l4evdev.c
l4/pkg/input/lib/src/ux.c
l4/pkg/io/config/arm-rv-eb-mc.devs
l4/pkg/io/config/arm-rv-eb-pbx.devs [new file with mode: 0644]
l4/pkg/io/server/src/debug.cc
l4/pkg/io/server/src/main.cc
l4/pkg/io/server/src/server.cc
l4/pkg/io/server/src/vbus.cc
l4/pkg/io/server/src/vbus.h
l4/pkg/io/server/src/vdevice.cc
l4/pkg/io/server/src/vdevice.h
l4/pkg/io/server/src/vicu.cc
l4/pkg/io/server/src/vicu.h
l4/pkg/io/server/src/vpci.cc
l4/pkg/io/server/src/vpci.h
l4/pkg/io/server/src/vpci_pci_bridge.h
l4/pkg/io/server/src/vpci_root_bridge.cc
l4/pkg/io/server/src/vpci_virtual_root.cc
l4/pkg/l4con/lib/client_con/con.cc
l4/pkg/l4con/server/src/server.cc
l4/pkg/l4re/Makefile
l4/pkg/l4re/include/impl/dataspace_impl.h
l4/pkg/l4re/include/impl/mem_alloc_impl.h
l4/pkg/l4re/include/impl/namespace_impl.h
l4/pkg/l4re/include/impl/rm_impl.h
l4/pkg/l4re/lib/src/debug.cc
l4/pkg/l4re/lib/src/event.cc
l4/pkg/l4re/lib/src/parent.cc
l4/pkg/l4re/lib/src/video/goos.cc
l4/pkg/l4re/lib/src/video/view.cc
l4/pkg/l4re/util/include/dataspace_svr
l4/pkg/l4re/util/include/event_svr
l4/pkg/l4re/util/include/icu_svr
l4/pkg/l4re/util/include/meta
l4/pkg/l4re/util/include/name_space_svr
l4/pkg/l4re/util/include/region_mapping_svr
l4/pkg/l4re/util/include/vcon_svr
l4/pkg/l4re/util/include/video/goos_svr
l4/pkg/l4re/util/libs/dataspace_svr.cc
l4/pkg/l4re/util/libs/name_space_svr.cc
l4/pkg/l4re_kernel/Control
l4/pkg/l4re_kernel/server/src/Makefile
l4/pkg/l4re_kernel/server/src/dispatcher.cc
l4/pkg/l4re_kernel/server/src/dispatcher.h
l4/pkg/l4re_kernel/server/src/main.cc
l4/pkg/l4re_kernel/server/src/region.cc
l4/pkg/l4re_kernel/server/src/region.h
l4/pkg/l4sys/include/compiler.h
l4/pkg/l4sys/include/debugger
l4/pkg/l4sys/include/debugger.h
l4/pkg/l4sys/include/typeinfo_svr
l4/pkg/l4util/include/ARCH-amd64/L4API-l4f/l4_macros.h
l4/pkg/l4util/include/ARCH-arm/L4API-l4f/l4_macros.h
l4/pkg/l4util/include/ARCH-x86/L4API-l4f/l4_macros.h
l4/pkg/l4util/include/base64.h
l4/pkg/l4util/include/rand.h
l4/pkg/l4util/include/slmap.h
l4/pkg/l4util/lib/src/ARCH-x86/apic.c
l4/pkg/l4util/lib/src/ARCH-x86/rdtsc.c
l4/pkg/l4util/lib/src/ARCH-x86/spin.c
l4/pkg/l4util/lib/src/alloc.c
l4/pkg/l4util/lib/src/base64.c
l4/pkg/l4util/lib/src/kip.c
l4/pkg/l4util/lib/src/kprintf.c
l4/pkg/l4util/lib/src/list_alloc.c
l4/pkg/l4util/lib/src/micros2l4to.c
l4/pkg/l4util/lib/src/parse_cmdline.c
l4/pkg/l4util/lib/src/rand.c
l4/pkg/l4util/lib/src/reboot.c
l4/pkg/l4util/lib/src/sleep.c
l4/pkg/l4util/lib/src/slmap.c
l4/pkg/libc_backends/lib/sig/lib/sig.cc
l4/pkg/libgfxbitmap/include/font.h
l4/pkg/libgfxbitmap/lib/src/font.c
l4/pkg/libkproxy/include/factory_svr
l4/pkg/libkproxy/include/scheduler_svr
l4/pkg/libkproxy/lib/src/factory_svr.cc
l4/pkg/libkproxy/lib/src/scheduler_svr.cc
l4/pkg/libloader/include/remote_app_model
l4/pkg/libpng/lib/README
l4/pkg/libpng/lib/build/config.h
l4/pkg/libpng/lib/build/pnglibconf.h
l4/pkg/libpng/lib/dist/ANNOUNCE
l4/pkg/libpng/lib/dist/CHANGES
l4/pkg/libpng/lib/dist/CMakeLists.txt
l4/pkg/libpng/lib/dist/LICENSE
l4/pkg/libpng/lib/dist/Makefile.am
l4/pkg/libpng/lib/dist/Makefile.in
l4/pkg/libpng/lib/dist/README
l4/pkg/libpng/lib/dist/configure
l4/pkg/libpng/lib/dist/configure.ac
l4/pkg/libpng/lib/dist/example.c
l4/pkg/libpng/lib/dist/libpng-manual.txt
l4/pkg/libpng/lib/dist/libpng.3
l4/pkg/libpng/lib/dist/libpngpf.3
l4/pkg/libpng/lib/dist/png.5
l4/pkg/libpng/lib/dist/png.c
l4/pkg/libpng/lib/dist/png.h
l4/pkg/libpng/lib/dist/pngconf.h
l4/pkg/libpng/lib/dist/pngerror.c
l4/pkg/libpng/lib/dist/pnginfo.h
l4/pkg/libpng/lib/dist/pngmem.c
l4/pkg/libpng/lib/dist/pngpread.c
l4/pkg/libpng/lib/dist/pngpriv.h
l4/pkg/libpng/lib/dist/pngread.c
l4/pkg/libpng/lib/dist/pngrtran.c
l4/pkg/libpng/lib/dist/pngrutil.c
l4/pkg/libpng/lib/dist/pngset.c
l4/pkg/libpng/lib/dist/pngstruct.h
l4/pkg/libpng/lib/dist/pngtest.c
l4/pkg/libpng/lib/dist/pngtest.png
l4/pkg/libpng/lib/dist/pngtrans.c
l4/pkg/libpng/lib/dist/pngvalid.c
l4/pkg/libpng/lib/dist/pngwrite.c
l4/pkg/libpng/lib/dist/pngwtran.c
l4/pkg/libpng/lib/dist/pngwutil.c
l4/pkg/libpng/lib/dist/scripts/README.txt
l4/pkg/libpng/lib/dist/scripts/libpng-config-head.in
l4/pkg/libpng/lib/dist/scripts/libpng.pc.in
l4/pkg/libpng/lib/dist/scripts/makefile.cegcc
l4/pkg/libpng/lib/dist/scripts/makefile.linux
l4/pkg/libpng/lib/dist/scripts/makefile.ne12bsd
l4/pkg/libpng/lib/dist/scripts/makefile.netbsd
l4/pkg/libpng/lib/dist/scripts/makefile.openbsd
l4/pkg/libpng/lib/dist/scripts/options.awk
l4/pkg/libpng/lib/dist/scripts/pnglibconf.dfa
l4/pkg/libpng/lib/dist/scripts/pnglibconf.h.prebuilt
l4/pkg/libpng/lib/dist/scripts/pnglibconf.mak
l4/pkg/libpng/lib/dist/scripts/symbols.def
l4/pkg/libpng/lib/dist/test-pngvalid-full.sh
l4/pkg/libsigma0/lib/src/anypage.c
l4/pkg/libsigma0/lib/src/client.c
l4/pkg/libsigma0/lib/src/debug.c
l4/pkg/libsigma0/lib/src/iomem.c
l4/pkg/libsigma0/lib/src/kip.c
l4/pkg/libsigma0/lib/src/mem.c
l4/pkg/libsigma0/lib/src/tbuf.c
l4/pkg/libstdc++-v3/contrib.inc
l4/pkg/libvbus/include/vbus_generic
l4/pkg/libvbus/lib/src/vbus.cc
l4/pkg/libvbus/lib/src/vbus_gpio.cc
l4/pkg/libvbus/lib/src/vbus_i2c.cc
l4/pkg/libvbus/lib/src/vbus_mcspi.cc
l4/pkg/libvbus/lib/src/vbus_pci.cc
l4/pkg/libvcpu/include/vcpu
l4/pkg/loader/server/src/Makefile
l4/pkg/loader/server/src/alloc.cc
l4/pkg/loader/server/src/alloc.h
l4/pkg/loader/server/src/app_task.cc
l4/pkg/loader/server/src/app_task.h
l4/pkg/loader/server/src/log.cc
l4/pkg/loader/server/src/log.h
l4/pkg/loader/server/src/main.cc
l4/pkg/loader/server/src/name_space.cc
l4/pkg/loader/server/src/name_space.h
l4/pkg/loader/server/src/region.cc
l4/pkg/loader/server/src/region.h
l4/pkg/loader/server/src/sched_proxy.cc
l4/pkg/loader/server/src/sched_proxy.h
l4/pkg/log/include/log.h
l4/pkg/log/lib/src/log.c
l4/pkg/mag/plugins/client_fb/client_fb.cc
l4/pkg/mag/plugins/client_fb/client_fb.h
l4/pkg/mag/plugins/client_fb/service.cc
l4/pkg/mag/plugins/client_fb/service.h
l4/pkg/mag/plugins/mag_client/mag_client.cc
l4/pkg/mag/server/src/Makefile
l4/pkg/mag/server/src/main.cc
l4/pkg/mag/server/src/object_gc.cc
l4/pkg/moe/server/src/alloc.cc
l4/pkg/moe/server/src/alloc.h
l4/pkg/moe/server/src/app_task.cc
l4/pkg/moe/server/src/app_task.h
l4/pkg/moe/server/src/dataspace.cc
l4/pkg/moe/server/src/dataspace.h
l4/pkg/moe/server/src/log.cc
l4/pkg/moe/server/src/log.h
l4/pkg/moe/server/src/main.cc
l4/pkg/moe/server/src/name_space.cc
l4/pkg/moe/server/src/name_space.h
l4/pkg/moe/server/src/region.cc
l4/pkg/moe/server/src/region.h
l4/pkg/moe/server/src/sched_proxy.cc
l4/pkg/moe/server/src/sched_proxy.h
l4/pkg/moe/server/src/vesa_fb.cc
l4/pkg/ned/server/src/Makefile
l4/pkg/ned/server/src/app_task.cc
l4/pkg/ned/server/src/app_task.h
l4/pkg/ned/server/src/lua_cap.cc
l4/pkg/ned/server/src/lua_exec.cc
l4/pkg/python/interpreter/Makefile
l4/pkg/rtc/lib/client/librtc.cc
l4/pkg/rtc/server/src/Makefile
l4/pkg/rtc/server/src/main.cc
l4/pkg/scout/lib/src/main.cc
l4/pkg/scout/mk/scout.mk
l4/pkg/serial-drv/server/src/main.cc
l4/pkg/slab/lib/src/Makefile
l4/pkg/slab/lib/src/slab.c
l4/pkg/spafs/server/src/Makefile
l4/pkg/spafs/server/src/main.cc
l4/pkg/sqlite/lib/README
l4/pkg/sqlite/lib/contrib/Makefile.in
l4/pkg/sqlite/lib/contrib/configure
l4/pkg/sqlite/lib/contrib/configure.ac
l4/pkg/sqlite/lib/contrib/shell.c
l4/pkg/sqlite/lib/contrib/sqlite3.c
l4/pkg/sqlite/lib/contrib/sqlite3.h
l4/pkg/sqlite/lib/contrib/sqlite3.pc
l4/pkg/uclibc/Control
l4/pkg/uclibc/lib/Makefile
l4/pkg/uclibc/lib/libpthread/src/sysdeps/arm/pt-machine.h
l4/pkg/uclibc/lib/minimal_l4re/Makefile [new file with mode: 0644]
l4/pkg/uclibc/lib/uclibc/Make.rules
l4/pkg/uclibc/lib/uclibc/_exit.cc [new file with mode: 0644]
l4/pkg/uclibc/lib/uclibc/make_rules.mk
l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/l4re/loop_hooks
l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/l4re/rm_init.cpp
l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/l4re/vcap.cpp
l4/tool/bin/qemu-x86-launch
l4/tool/kconfig/Makefile
l4/tool/kconfig/README
l4/tool/kconfig/scripts/Kbuild.include
l4/tool/kconfig/scripts/Makefile
l4/tool/kconfig/scripts/Makefile.build
l4/tool/kconfig/scripts/Makefile.headersinst
l4/tool/kconfig/scripts/Makefile.lib
l4/tool/kconfig/scripts/basic/Makefile
l4/tool/kconfig/scripts/kconfig/Makefile
l4/tool/kconfig/scripts/kconfig/confdata.c
l4/tool/kconfig/scripts/kconfig/expr.h
l4/tool/kconfig/scripts/kconfig/gconf.c
l4/tool/kconfig/scripts/kconfig/lex.zconf.c_shipped
l4/tool/kconfig/scripts/kconfig/nconf.c
l4/tool/kconfig/scripts/kconfig/qconf.cc
l4/tool/kconfig/scripts/kconfig/zconf.l

index 38c4e678066a58d7eaafb8ba89f6e65df120582d..ef68efc4a232d773a583223b2ea0208dd9012ec0 100644 (file)
@@ -98,6 +98,8 @@ config CAN_ARM_CPU_CORTEX_A8
 config CAN_ARM_CPU_CORTEX_A9
        bool
 
+config CAN_ARM_CACHE_L2CXX0
+       bool
 
 choice
        prompt "CPU"
@@ -283,6 +285,13 @@ config ARM_CA9_ENABLE_SWP
          Enabling this option enables the deprecated 'swp' instruction.
          Avoid to enable it.
 
+config ARM_CACHE_L2CXX0
+       bool "Enable L2 Cache"
+       default y
+       depends on CAN_ARM_CACHE_L2CXX0
+       help 
+         Enable L2 cache functionality.
+
 choice
        prompt "Timer tick source"
        depends on PF_PC || PF_UX
@@ -382,8 +391,7 @@ config MP
 config MP_MAX_CPUS
        int "Maximal supported number of CPUs"
        depends on MP
-       range 1 32 if BIT32
-       range 1 64 if BIT64
+       range 1 128
        default 4
        help
          The maximum number of CPUs the kernel supports.
@@ -439,7 +447,7 @@ config ONE_SHOT
          possible.  EXPERIMENTAL!
 
 config SYNC_TSC
-       bool "Synchronize KIP time with time-stamp counter"
+       bool "Use time-stamp counter for KIP and scheduling accounting"
        depends on PF_PC && IA32
        help
          Synchronize the internal kernel clock with the CPU time stamp
index fc4b006021f4821d2df59495eaf79c1b3abecd23..44c9b2e5c65714eb2f1e7c2a7abdd6afe2794803 100644 (file)
@@ -12,6 +12,6 @@ SHARED_FLAGS-$(CONFIG_ARM_CORTEX_A8) += $(call CHECKCC,-mcpu=cortex-a8)
 SHARED_FLAGS-$(CONFIG_ARM_CORTEX_A9) += $(call CHECKCC,-mcpu=cortex-a9)
 SHARED_FLAGS                     += -msoft-float
 SHARED_FLAGS                      += $(call CHECKCC,-mno-thumb-interwork)
-SHARED_FLAGS                      += -mabi=apcs-gnu
+SHARED_FLAGS                      += -marm -mabi=apcs-gnu
 LDFLAGS                           += --no-warn-mismatch
 LD_EMULATION_CHOICE               := armelf armelf_linux_eabi armelf_fbsd
index 5ff3c9136cf2a2a470a204a840d7197d4902a18e..6aeafe09d4d21dc192b44bec7b605215db5b8de9 100644 (file)
@@ -18,6 +18,7 @@ PREPROCESS_PARTS-$(CONFIG_FPU)                += fpu
 PREPROCESS_PARTS-$(CONFIG_LIST_ALLOC_SANITY)  += list_alloc_debug
 PREPROCESS_PARTS-$(CONFIG_JDB)                += debug jdb log
 PREPROCESS_PARTS-$(CONFIG_PERF_CNT)           += perf_cnt
+PREPROCESS_PARTS-$(CONFIG_ARM_CACHE_L2CXX0)   += outer_cache outer_cache_l2cxx0
 
 PREPROCESS_PARTS-$(CONFIG_ARM_920T)                 += armv5 arm920t vcache
 PREPROCESS_PARTS-$(CONFIG_ARM_926)                  += armv5 926 vcache
@@ -150,7 +151,7 @@ PREPROCESS_PARTS    += ulock
 INTERFACES_KERNEL      += u_semaphore
 
 INTERFACES_KERNEL-$(CONFIG_SERIAL) += uart_console
-INTERFACES_KERNEL-$(CONFIG_ARM_TZ)     += vm
+INTERFACES_KERNEL-$(CONFIG_ARM_TZ) += vm
 
 INTERFACES_KERNEL += $(INTERFACES_KERNEL-y)
 
@@ -178,7 +179,7 @@ mem_layout_IMPL             := mem_layout mem_layout-arm mem_layout-noncont
 mem_space_IMPL         := mem_space mem_space-arm mem_space-user
 kmem_alloc_IMPL                := kmem_alloc kmem_alloc-arm
 obj_space_IMPL          := obj_space obj_space-$(OBJ_SPACE_TYPE)
-outer_cache_IMPL       := outer_cache
+outer_cache_IMPL       := outer_cache outer_cache-l2cxx0
 pagetable_IMPL         := pagetable pagetable-arch
 paging_IMPL            := paging-arm paging
 perf_cnt_IMPL          := perf_cnt perf_cnt-arm
index f1dcb1178ec1206fac592133d09a6dc79fb376bd..c8f81a41907765f97d7a89e19a5630e5b4a72108 100644 (file)
@@ -37,12 +37,13 @@ public:
 
 protected:
   enum {
-    Op_set_name     = 0,
-    Op_global_id    = 1,
-    Op_kobj_to_id   = 2,
-    Op_query_typeid = 3,
-    Op_switch_log   = 4,
-    Op_get_name     = 5,
+    Op_set_name         = 0,
+    Op_global_id        = 1,
+    Op_kobj_to_id       = 2,
+    Op_query_log_typeid = 3,
+    Op_switch_log       = 4,
+    Op_get_name         = 5,
+    Op_query_log_name   = 6,
   };
 private:
   Jdb_kobject_handler *_next;
index ad93affa6ef58604f7451a73ea035813b254db9d..936b7c0e0b384f22933a020d72b03ba1739e4814 100644 (file)
@@ -45,17 +45,10 @@ Jdb_log_list_hdl::invoke(Kobject_common *, Syscall_frame *f, Utcb *utcb)
 {
   switch (utcb->values[0])
     {
-      case Op_query_typeid:
+      case Op_query_log_typeid:
           {
-            if (f->tag().words() < 3)
-              {
-                f->tag(Kobject_iface::commit_result(-L4_err::EInval));
-                return true;
-              }
-
             unsigned char const idx = utcb->values[1];
-
-            if (_log_table + idx >= &_log_table_end)
+            if (f->tag().words() < 3 || _log_table + idx >= &_log_table_end)
               {
                 f->tag(Kobject_iface::commit_result(-L4_err::EInval));
                 return true;
@@ -72,6 +65,27 @@ Jdb_log_list_hdl::invoke(Kobject_common *, Syscall_frame *f, Utcb *utcb)
             f->tag(Kobject_iface::commit_result(0, 1));
             return true;
           }
+      case Op_query_log_name:
+          {
+            unsigned char const idx = utcb->values[1];
+            if (f->tag().words() != 2 || _log_table + idx >= &_log_table_end)
+              {
+                f->tag(Kobject_iface::commit_result(-L4_err::EInval));
+                return true;
+              }
+
+            Tb_log_table_entry *e = _log_table + idx;
+           char *dst = (char *)&utcb->values[0];
+            unsigned sz = strlen(e->name) + 1;
+            sz += strlen(e->name + sz) + 1;
+            if (sz > sizeof(utcb->values))
+              sz = sizeof(utcb->values);
+            memcpy(dst, e->name, sz);
+            dst[sz - 1] = 0;
+
+            f->tag(Kobject_iface::commit_result(0));
+            return true;
+          }
       case Op_switch_log:
           {
             if (f->tag().words() < 3)
index d009dcd6b3de1187c652bd99494ddfaf70ebe6ee..447046f9085dc0a26f75a747afbe536a7c5075a5 100644 (file)
@@ -157,7 +157,9 @@ extern "C" void bootstrap_main()
   set_asid();
 
   asm volatile (
-      "mcr p15, 0, %[null], c8, c7, 0x00   \n" // TLB flush
+      "mcr p15, 0, %[null], c7, c10, 4\n" // dsb
+      "mcr p15, 0, %[null], c8, c7, 0 \n" // tlb flush
+      "mcr p15, 0, %[null], c7, c10, 4\n" // dsb
       "mcr p15, 0, %[doms], c3, c0    \n" // domains
       "mcr p15, 0, %[pdir], c2, c0    \n" // pdbr
       "mcr p15, 0, %[control], c1, c0 \n" // control
index f7cc6e632dda3dd748038647297f8a15d0c488cb..1b42875bda1806cc43477ae039c60550abece47d 100644 (file)
@@ -14,6 +14,7 @@ config PF_REALVIEW_EB
        select CAN_ARM_CPU_MPCORE
        select CAN_ARM_CPU_CORTEX_A8
        select CAN_ARM_CPU_CORTEX_A9
+       select CAN_ARM_CACHE_L2CXX0 if ARM_MPCORE
        help
          Choose for Emulation Baseboard (EB)
 
@@ -21,6 +22,7 @@ config PF_REALVIEW_PB11MP
        bool "PB11MP"
        depends on PF_REALVIEW
        select CAN_ARM_CPU_MPCORE
+       select CAN_ARM_CACHE_L2CXX0
        help
          Choose for PB11MP
 
@@ -28,6 +30,7 @@ config PF_REALVIEW_PBX
        bool "PBX"
        depends on PF_REALVIEW
        select CAN_ARM_CPU_CORTEX_A9
+       select CAN_ARM_CACHE_L2CXX0
        help
          Choose for PBX-A9.
 
@@ -66,8 +69,3 @@ config PF_REALVIEW_RAM_PHYS_BASE
        default 0x20000000 if PF_REALVIEW_RAM_PHYS_BASE_0x2
        default 0x60000000 if PF_REALVIEW_RAM_PHYS_BASE_0x6
        default 0x70000000 if PF_REALVIEW_RAM_PHYS_BASE_0x7
-
-config PF_REALVIEW_L2CACHE
-       bool "Enable L2 Cache"
-       default y
-       depends on PF_REALVIEW_PB11MP || PF_REALVIEW_PBX || ARM_MPCORE
index 709168b635a6695ea37cf81aa07c679d48447d80..2b416413d66f1f54587921f99d5ef6900b7b3343 100644 (file)
@@ -3,7 +3,6 @@
 SUBSYSTEMS              += LIBUART
 OBJECTS_LIBUART         += uart_pl011.o
 PREPROCESS_PARTS        += realview libuart pic_gic
-PREPROCESS_PARTS        += $(if $(CONFIG_PF_REALVIEW_L2CACHE),outer_cache)
 PREPROCESS_PARTS        += $(if $(CONFIG_PF_REALVIEW_EB),realview_eb)
 PREPROCESS_PARTS        += $(if $(CONFIG_PF_REALVIEW_PB11MP),realview_pb11mp)
 PREPROCESS_PARTS        += $(if $(CONFIG_PF_REALVIEW_PBX),realview_pbx)
index 41f2896762fa2f1badeb41b519e1eeecf04b01bb..5ee295aaa1f785cfee65cd66f5a6db6e01d51a54 100644 (file)
@@ -75,7 +75,7 @@ public:
     Mp_scu_map_base      = Devices1_map_base,
     Gic_cpu_map_base     = Devices1_map_base + 0x00000100,
     Gic_dist_map_base    = Devices1_map_base + 0x00001000,
-    L220_map_base        = Devices1_map_base + 0x00002000,
+    L2cxx0_map_base      = Devices1_map_base + 0x00002000,
 
     Gic1_cpu_map_base    = Devices0_map_base + 0x00040000,
     Gic1_dist_map_base   = Devices0_map_base + 0x00041000,
@@ -85,7 +85,7 @@ public:
     Mp_scu_phys_base     = 0x1f000000,
     Gic_cpu_phys_base    = Mp_scu_phys_base  + 0x00000100,
     Gic_dist_phys_base   = Mp_scu_phys_base  + 0x00001000,
-    L220_phys_base       = Mp_scu_phys_base  + 0x00002000,
+    L2cxx0_phys_base     = Mp_scu_phys_base  + 0x00002000,
 
     Gic1_cpu_phys_base   = Devices0_phys_base + 0x00040000,
     Gic1_dist_phys_base  = Devices0_phys_base + 0x00041000,
@@ -108,7 +108,7 @@ public:
     Mp_scu_map_base      = Devices1_map_base,
     Gic_cpu_map_base     = Devices1_map_base + 0x00000100,
     Gic_dist_map_base    = Devices1_map_base + 0x00001000,
-    L220_map_base        = Devices1_map_base + 0x00002000,
+    L2cxx0_map_base      = Devices1_map_base + 0x00002000,
 
     Gic1_cpu_map_base    = Devices2_map_base,
     Gic1_dist_map_base   = Devices2_map_base + 0x00001000,
@@ -119,7 +119,7 @@ public:
     Mp_scu_phys_base     = 0x1f000000,
     Gic_cpu_phys_base    = Mp_scu_phys_base + 0x00000100,
     Gic_dist_phys_base   = Mp_scu_phys_base + 0x00001000,
-    L220_phys_base       = Mp_scu_phys_base + 0x00002000,
+    L2cxx0_phys_base     = Mp_scu_phys_base + 0x00002000,
 
     Devices2_phys_base   = 0x1e000000,
     Gic0_cpu_phys_base   = 0x1e000000,
@@ -139,7 +139,7 @@ public:
     Mp_scu_map_base      = Devices1_map_base,
     Gic_cpu_map_base     = Devices1_map_base + 0x00000100,
     Gic_dist_map_base    = Devices1_map_base + 0x00001000,
-    L220_map_base        = Devices1_map_base + 0x00002000,
+    L2cxx0_map_base      = Devices1_map_base + 0x00002000,
 
     Gic2_cpu_map_base    = Devices2_map_base + 0x00020000,
     Gic2_dist_map_base   = Devices2_map_base + 0x00021000,
@@ -152,7 +152,7 @@ public:
     Mp_scu_phys_base     = 0x1f000000,
     Gic_cpu_phys_base    = Mp_scu_phys_base + 0x00000100,
     Gic_dist_phys_base   = Mp_scu_phys_base + 0x00001000,
-    L220_phys_base       = Mp_scu_phys_base + 0x00002000,
+    L2cxx0_phys_base     = Mp_scu_phys_base + 0x00002000,
 
     Devices2_phys_base   = 0x1e000000,
     Gic2_cpu_phys_base   = 0x1e020000,
@@ -172,7 +172,7 @@ public:
     Mp_scu_map_base      = Devices1_map_base,
     Gic_cpu_map_base     = Devices1_map_base + 0x00000100,
     Gic_dist_map_base    = Devices1_map_base + 0x00001000,
-    L220_map_base        = Devices1_map_base + 0x00002000,
+    L2cxx0_map_base      = Devices1_map_base + 0x00002000,
   };
 
   enum Phys_layout_realview_vexpress {
@@ -180,6 +180,6 @@ public:
     Mp_scu_phys_base     = 0x1e000000,
     Gic_cpu_phys_base    = Mp_scu_phys_base + 0x00000100,
     Gic_dist_phys_base   = Mp_scu_phys_base + 0x00001000,
-    L220_phys_base       = Mp_scu_phys_base + 0x00002000,
+    L2cxx0_phys_base     = Mp_scu_phys_base + 0x00002000,
   };
 };
index dc5c58f53c839567fb2310d9556b801168474fb7..a350b813db84ba806f13b52ae0f8714e42d57945 100644 (file)
@@ -1,144 +1,9 @@
-INTERFACE [arm && realview && outer_cache]:
-
-#include "mem_layout.h"
-#include "spin_lock.h"
-
-EXTENSION class Outer_cache
-{
-private:
-  enum
-  {
-    Cache_line_shift = 5,
-
-
-    CACHE_ID                       = Mem_layout::L220_map_base + 0x000,
-    CACHE_TYPE                     = Mem_layout::L220_map_base + 0x004,
-    CONTROL                        = Mem_layout::L220_map_base + 0x100,
-    AUX_CONTROL                    = Mem_layout::L220_map_base + 0x104,
-    TAG_RAM_CONTROL                = Mem_layout::L220_map_base + 0x108,
-    DATA_RAM_CONTROL               = Mem_layout::L220_map_base + 0x10c,
-    EVENT_COUNTER_CONTROL          = Mem_layout::L220_map_base + 0x200,
-    EVENT_COUTNER1_CONFIG          = Mem_layout::L220_map_base + 0x204,
-    EVENT_COUNTER0_CONFIG          = Mem_layout::L220_map_base + 0x208,
-    EVENT_COUNTER1_VALUE           = Mem_layout::L220_map_base + 0x20c,
-    EVENT_COUNTER0_VALUE           = Mem_layout::L220_map_base + 0x210,
-    INTERRUPT_MASK                 = Mem_layout::L220_map_base + 0x214,
-    MASKED_INTERRUPT_STATUS        = Mem_layout::L220_map_base + 0x218,
-    RAW_INTERRUPT_STATUS           = Mem_layout::L220_map_base + 0x21c,
-    INTERRUPT_CLEAR                = Mem_layout::L220_map_base + 0x220,
-    CACHE_SYNC                     = Mem_layout::L220_map_base + 0x730,
-    INVALIDATE_LINE_BY_PA          = Mem_layout::L220_map_base + 0x770,
-    INVALIDATE_BY_WAY              = Mem_layout::L220_map_base + 0x77c,
-    CLEAN_LINE_BY_PA               = Mem_layout::L220_map_base + 0x7b0,
-    CLEAN_LINE_BY_INDEXWAY         = Mem_layout::L220_map_base + 0x7bb,
-    CLEAN_BY_WAY                   = Mem_layout::L220_map_base + 0x7bc,
-    CLEAN_AND_INV_LINE_BY_PA       = Mem_layout::L220_map_base + 0x7f0,
-    CLEAN_AND_INV_LINE_BY_INDEXWAY = Mem_layout::L220_map_base + 0x7f8,
-    CLEAN_AND_INV_BY_WAY           = Mem_layout::L220_map_base + 0x7fc,
-    LOCKDOWN_BY_WAY_D_SIDE         = Mem_layout::L220_map_base + 0x900,
-    LOCKDOWN_BY_WAY_I_SIDE         = Mem_layout::L220_map_base + 0x904,
-    TEST_OPERATION                 = Mem_layout::L220_map_base + 0xf00,
-    LINE_TAG                       = Mem_layout::L220_map_base + 0xf30,
-    DEBUG_CONTROL_REGISTER         = Mem_layout::L220_map_base + 0xf40,
-
-  };
-
-  static Spin_lock<> _lock;
-
-public:
-  enum
-  {
-    Cache_line_size = 1 << Cache_line_shift,
-    Cache_line_mask = Cache_line_size - 1,
-  };
-};
-
 // ------------------------------------------------------------------------
-IMPLEMENTATION [arm && realview && outer_cache]:
-
-#include "io.h"
-#include "static_init.h"
-#include "lock_guard.h"
-
-#include <cstdio>
-
-Spin_lock<> Outer_cache::_lock;
-
-IMPLEMENT inline NEEDS ["io.h"]
-void
-Outer_cache::sync()
-{
-  while (Io::read<Mword>(CACHE_SYNC))
-    ;
-}
-
-PRIVATE static inline NEEDS ["io.h", "lock_guard.h"]
-void
-Outer_cache::write(Address reg, Mword val)
-{
-  Lock_guard<Spin_lock<> > guard(&_lock);
-  Io::write<Mword>(val, reg);
-  while (Io::read<Mword>(reg) & 1)
-    ;
-}
+IMPLEMENTATION [arm && realview && outer_cache_l2cxx0 && armca9]:
 
-IMPLEMENT inline NEEDS[Outer_cache::write]
+IMPLEMENT
 void
-Outer_cache::clean()
-{
-  write(CLEAN_BY_WAY, 0xff);
-  sync();
-}
-
-IMPLEMENT inline NEEDS[Outer_cache::write]
-void
-Outer_cache::clean(Mword phys_addr, bool do_sync = true)
-{
-  write(CLEAN_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
-  if (do_sync)
-    sync();
-}
-
-IMPLEMENT inline NEEDS[Outer_cache::write]
-void
-Outer_cache::flush()
-{
-  write(CLEAN_BY_WAY, 0xff);
-  sync();
-}
-
-IMPLEMENT inline NEEDS[Outer_cache::write]
-void
-Outer_cache::flush(Mword phys_addr, bool do_sync = true)
-{
-  write(CLEAN_AND_INV_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
-  if (do_sync)
-    sync();
-}
-
-IMPLEMENT inline NEEDS[Outer_cache::write]
-void
-Outer_cache::invalidate()
-{
-  write(INVALIDATE_BY_WAY, 0xff);
-  sync();
-}
-
-IMPLEMENT inline NEEDS[Outer_cache::write]
-void
-Outer_cache::invalidate(Address phys_addr, bool do_sync = true)
-{
-  write(INVALIDATE_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
-  if (do_sync)
-    sync();
-}
-
-// ------------------------------------------------------------------------
-IMPLEMENTATION [arm && realview && outer_cache && armca9]:
-
-PRIVATE static inline
-void
-Outer_cache::init_plat()
+Outer_cache::platform_init()
 {
   Io::write<Mword>(0 , TAG_RAM_CONTROL);
   Io::write<Mword>(0 , DATA_RAM_CONTROL);
@@ -153,11 +18,11 @@ Outer_cache::init_plat()
 }
 
 // ------------------------------------------------------------------------
-IMPLEMENTATION [arm && realview && outer_cache && mpcore]:
+IMPLEMENTATION [arm && realview && outer_cache_l2cxx0 && mpcore]:
 
-PRIVATE static inline
+IMPLEMENT
 void
-Outer_cache::init_plat()
+Outer_cache::platform_init()
 {
   Mword aux_control = Io::read<Mword>(AUX_CONTROL);
   aux_control &= 0xfe000fff; // keep latencies, keep reserved, keep NS bits
@@ -166,32 +31,3 @@ Outer_cache::init_plat()
   aux_control |= 1 << 22; // shared bit ignore
   Io::write<Mword>(aux_control, AUX_CONTROL);
 }
-
-// ------------------------------------------------------------------------
-IMPLEMENTATION [arm && realview && outer_cache]:
-
-PUBLIC static
-void
-Outer_cache::init()
-{
-  printf("L2: ID=%08lx Type=%08lx\n",
-         Io::read<Mword>(CACHE_ID),
-         Io::read<Mword>(CACHE_TYPE));
-
-  // disable
-  Io::write(0, CONTROL);
-
-  init_plat();
-
-  Io::write<Mword>(0, INTERRUPT_MASK);
-
-  invalidate();
-  Io::write<Mword>(~0UL, INTERRUPT_CLEAR);
-
-  // enable
-  Io::write(1, CONTROL);
-
-  printf("L2 cache enabled\n");
-}
-
-STATIC_INITIALIZE_P(Outer_cache, STARTUP_INIT_PRIO);
index b0cf3471c782c63338db0baacca562dec25a7256..66d0ed9ab032ff535d89a1d1f71fbf4a372ec88a 100644 (file)
@@ -1,4 +1,4 @@
 # PF: TEGRA2
 # PFDESCR: NVIDIA Tegra 2xx platform
-# PFCAN: CAN_ARM_CPU_CORTEX_A9
+# PFCAN: CAN_ARM_CPU_CORTEX_A9 CAN_ARM_CACHE_L2CXX0
 # PFDEPENDS: ARM
index a72959342e8a1f9daae7c8810bee74047584fc88..d86f04f4417cf3c831550f94e312f68da6c57a3e 100644 (file)
@@ -15,3 +15,4 @@ kernel_uart_IMPL      += kernel_uart-arm-tegra2
 reset_IMPL            += reset-arm-tegra2
 clock_IMPL            += clock-generic
 boot_mp_IMPL          += boot_mp-arm-tegra2
+outer_cache_IMPL      += outer_cache-arm-tegra2
index c8113875b0bc3b339cc4c233db42f93d1c16e362..ff50b9244b45f61bf5e5da20201f20916886175a 100644 (file)
@@ -10,6 +10,7 @@ public:
     Devices2_map_base    = Registers_map_start + 0x00200000,
 
     Mp_scu_map_base      = Devices2_map_base + 0x00040000,
+    L2cxx0_map_base      = Devices2_map_base + 0x00043000,
 
     Gic_cpu_map_base     = Devices2_map_base + 0x00040100,
     Gic_dist_map_base    = Devices2_map_base + 0x00041000,
diff --git a/kernel/fiasco/src/kern/arm/bsp/tegra2/outer_cache-arm-tegra2.cpp b/kernel/fiasco/src/kern/arm/bsp/tegra2/outer_cache-arm-tegra2.cpp
new file mode 100644 (file)
index 0000000..c9b40f1
--- /dev/null
@@ -0,0 +1,19 @@
+IMPLEMENTATION [arm && tegra2 && outer_cache_l2cxx0]:
+
+IMPLEMENT
+void
+Outer_cache::platform_init()
+{
+  Io::write<Mword>(0x331, TAG_RAM_CONTROL);
+  Io::write<Mword>(0x441, DATA_RAM_CONTROL);
+
+  Mword aux_control = Io::read<Mword>(AUX_CONTROL);
+  aux_control &= 0x8200c3fe;
+  aux_control |=   (1 <<  0)  // Full Line of Zero Enable
+                 | (4 << 17)  // 128kb waysize
+                 | (1 << 28)  // data prefetch
+                 | (1 << 29)  // insn prefetch
+                 | (1 << 30)  // early BRESP enable
+                ;
+  Io::write<Mword>(aux_control, AUX_CONTROL);
+}
index 4d4c25ca92798716068930e96859332215608936..728f73ad4ba155739f370b686ef5e6334e1caa03 100644 (file)
@@ -1,7 +1,6 @@
 INTERFACE [arm && tegra2]:
 
 #include "gic.h"
-#include "kmem.h"
 
 class Irq_base;
 
@@ -25,6 +24,7 @@ IMPLEMENTATION [arm && pic_gic && tegra2]:
 #include "initcalls.h"
 #include "irq_chip.h"
 #include "irq_chip_generic.h"
+#include "kmem.h"
 
 Gic Gic_pin::_gic[1];
 
@@ -33,8 +33,7 @@ class Irq_chip_tegra2 : public Irq_chip_gen
 };
 
 PUBLIC
-void
-Irq_chip_tegra2::setup(Irq_base *irq, unsigned irqnum)
+void Irq_chip_tegra2::setup(Irq_base *irq, unsigned irqnum)
 {
   irq->pin()->replace<Gic_pin>(0, irqnum);
 }
index 6f541e600647899b13dc1753188af73dd0f8720a..a03ca91fbbf6a8c18b559005a6662e03b0b2822c 100644 (file)
@@ -80,21 +80,9 @@ IMPLEMENTATION [arm]:
 char const Config::char_micro = '\265';
 const char *const Config::kernel_warn_config_string = 0;
 
-//---------------------------------------------------------------------------
-IMPLEMENTATION [arm && serial]:
-
-IMPLEMENT FIASCO_INIT
-void Config::init()
-{
-  serial_esc = SERIAL_ESC_IRQ;
-}
-
-
-//---------------------------------------------------------------------------
-IMPLEMENTATION [arm && !serial]:
-
 IMPLEMENT FIASCO_INIT
-void Config::init()
+void
+Config::init_arch()
 {}
 
 //---------------------------------------------------------------------------
index e9660cf3eed0d65248befcbcc8301fab5137b68b..4809ffd8e78955ae200d707924039e7faa2c44eb 100644 (file)
@@ -10,6 +10,15 @@ private:
   bool _ignore_mem_op_in_progess;
 };
 
+// ------------------------------------------------------------------------
+INTERFACE [armv6plus]:
+
+EXTENSION class Context
+{
+private:
+  Mword _tpidrurw;
+};
+
 // ------------------------------------------------------------------------
 IMPLEMENTATION [arm]:
 
@@ -47,12 +56,13 @@ Context::spill_user_state()
       : "=m"(ef->usp), "=m"(ef->ulr) : [rf] "r" (&ef->usp));
 }
 
-IMPLEMENT inline
+IMPLEMENT inline NEEDS[Context::store_tpidrurw]
 void
 Context::switch_cpu(Context *t)
 {
   update_consumed_time();
 
+  store_tpidrurw();
   spill_user_state();
   t->fill_user_state();
 
@@ -111,6 +121,8 @@ void Context::switchin_context(Context *from)
   // switch to our page directory if nessecary
   vcpu_aware_space()->switchin_context(from->vcpu_aware_space());
 
+  load_tpidrurw();
+
   Utcb_support::current(utcb().usr());
 }
 
@@ -123,3 +135,32 @@ Context::set_ignore_mem_op_in_progress(bool val)
   Mem::barrier();
 }
 
+// ------------------------------------------------------------------------
+IMPLEMENTATION [armv6plus]:
+
+PRIVATE inline
+void
+Context::store_tpidrurw()
+{
+  asm volatile ("mrc p15, 0, %0, c13, c0, 2" : "=r" (_tpidrurw));
+}
+
+PRIVATE inline
+void
+Context::load_tpidrurw() const
+{
+  asm volatile ("mcr p15, 0, %0, c13, c0, 2" : : "r" (_tpidrurw));
+}
+
+// ------------------------------------------------------------------------
+IMPLEMENTATION [!armv6plus]:
+
+PRIVATE inline
+void
+Context::store_tpidrurw()
+{}
+
+PRIVATE inline
+void
+Context::load_tpidrurw() const
+{}
index d536188f07804e77286189355cbc6513e5a31aa7..cdbed02cc5554a22c6a133b5f2e8cfa18357b90b 100644 (file)
@@ -3,27 +3,26 @@ INTERFACE [arm && fpu]:
 EXTENSION class Fpu
 {
 public:
-  
   struct Exception_state_user
-    {
-      Mword fpexc;
-      Mword fpinst;
-      Mword fpinst2;
-    };
+  {
+    Mword fpexc;
+    Mword fpinst;
+    Mword fpinst2;
+  };
 
-private:
+  Mword fpsid() const { return _fpsid; }
 
   enum
-    {
-      FPEXC_EN  = 1 << 30,
-      FPEXC_EX  = 1 << 31,
-    };
+  {
+    FPEXC_EN  = 1 << 30,
+    FPEXC_EX  = 1 << 31,
+  };
 
   struct Fpu_regs
-    {
-      Mword fpexc, fpscr;
-      Mword state[32 * 4]; // 4*32 bytes for each FP-reg
-    };
+  {
+    Mword fpexc, fpscr;
+    Mword state[32 * 4]; // 4*32 bytes for each FP-reg
+  };
 
   static Mword fpsid_rev(Mword v)          { return v & 0xf; }
   static Mword fpsid_variant(Mword v)      { return (v >> 4) & 0xf; }
@@ -33,6 +32,9 @@ private:
   static Mword fpsid_format(Mword v)       { return (v >> 21) & 3; }
   static Mword fpsid_hw_sw(Mword v)        { return (v >> 23) & 1; }
   static Mword fpsid_implementer(Mword v)  { return v >> 24; }
+
+private:
+  Mword _fpsid;
 };
 
 // ------------------------------------------------------------------------
@@ -42,22 +44,8 @@ EXTENSION class Fpu
 {
 public:
   struct Exception_state_user
-    {
-    };
-};
-
-// ------------------------------------------------------------------------
-INTERFACE [arm]:
-
-EXTENSION class Fpu
-{
-public:
-  enum Fpu_exception_returns
-    {
-      Fpu_except_none,
-      Fpu_except_emulated,
-      Fpu_except_fault,
-    };
+  {
+  };
 };
 
 // ------------------------------------------------------------------------
@@ -70,21 +58,6 @@ void
 Fpu::save_user_exception_state(Trap_state *, Exception_state_user *)
 {}
 
-PUBLIC static inline NEEDS["trap_state.h"]
-Fpu::Fpu_exception_returns
-Fpu::handle_fpu_trap(Trap_state *)
-{ return Fpu::Fpu_except_none; }
-
-PUBLIC static inline
-bool
-Fpu::is_enabled()
-{ return false; }
-
-PUBLIC static inline
-bool
-Fpu::exc_pending()
-{ return false; }
-
 // ------------------------------------------------------------------------
 IMPLEMENTATION [arm && fpu]:
 
@@ -98,22 +71,39 @@ IMPLEMENTATION [arm && fpu]:
 #include "static_assert.h"
 #include "trap_state.h"
 
-PRIVATE static inline
+PUBLIC static inline
+Mword
+Fpu::fpsid_read()
+{
+  Mword v;
+  asm volatile("mrc p10, 7, %0, cr0, cr0" : "=r" (v));
+  return v;
+}
+
+PUBLIC static inline
 Mword
-Fpu::fpsid()
+Fpu::mvfr0()
 {
   Mword v;
-  //asm volatile("fmrx %0, fpsid" : "=r" (v));
-  asm volatile("mrc p10, 7, %0, cr0, cr0, 0" : "=r" (v));
+  asm volatile("mrc p10, 7, %0, cr7, cr0" : "=r" (v));
   return v;
 }
 
+PUBLIC static inline
+Mword
+Fpu::mvfr1()
+{
+  Mword v;
+  asm volatile("mrc p10, 7, %0, cr6, cr0" : "=r" (v));
+  return v;
+}
+
+
 PRIVATE static inline
 void
 Fpu::fpexc(Mword v)
 {
-  //asm volatile("fmxr fpexc, %0" : : "r" (v));
-  asm volatile("mcr p10, 7, %0, cr8, cr0, 0" : : "r" (v));
+  asm volatile("mcr p10, 7, %0, cr8, cr0" : : "r" (v));
 }
 
 PUBLIC static inline
@@ -121,8 +111,7 @@ Mword
 Fpu::fpexc()
 {
   Mword v;
-  //asm volatile("fmrx %0, fpexc" : "=r" (v));
-  asm volatile("mrc p10, 7, %0, cr8, cr0, 0" : "=r" (v));
+  asm volatile("mrc p10, 7, %0, cr8, cr0" : "=r" (v));
   return v;
 }
 
@@ -131,7 +120,7 @@ Mword
 Fpu::fpinst()
 {
   Mword i;
-  asm volatile("mcr p10, 7, %0, cr9,  cr0, 0" : "=r" (i));
+  asm volatile("mcr p10, 7, %0, cr9,  cr0" : "=r" (i));
   return i;
 }
 
@@ -140,7 +129,7 @@ Mword
 Fpu::fpinst2()
 {
   Mword i;
-  asm volatile("mcr p10, 7, %0, cr10,  cr0, 0" : "=r" (i));
+  asm volatile("mcr p10, 7, %0, cr10,  cr0" : "=r" (i));
   return i;
 }
 
@@ -165,17 +154,51 @@ Fpu::disable()
   fpexc(fpexc() & ~FPEXC_EN);
 }
 
+PUBLIC static inline
+bool
+Fpu::emulate_insns(Mword opcode, Trap_state *ts, unsigned cpu)
+{
+  unsigned reg = (opcode >> 16) & 0xf;
+  unsigned rt  = (opcode >> 12) & 0xf;
+  Mword fpsid = Fpu::fpu(cpu).fpsid();
+  switch (reg)
+    {
+    case 0: // FPSID
+      ts->r[rt] = fpsid;
+      break;
+    case 6: // MVFR1
+      if (Fpu::fpsid_arch_version(fpsid) < 2)
+        return false;
+      ts->r[rt] = Fpu::mvfr1();
+      break;
+    case 7: // MVFR0
+      if (Fpu::fpsid_arch_version(fpsid) < 2)
+        return false;
+      ts->r[rt] = Fpu::mvfr0();
+      break;
+    default:
+      break;
+    }
+
+  if (ts->psr & Proc::Status_thumb)
+    ts->pc += 2;
+
+  return true;
+}
+
 
 
 IMPLEMENT
 void
 Fpu::init(unsigned cpu)
 {
-  // XXX MPCORE: enable cp11, cp10
   asm volatile(" mcr  p15, 0, %0, c1, c0, 2   \n" : : "r"(0x00f00000));
   Mem::dsb();
 
-  Mword s = fpsid();
+  Mword s = fpsid_read();
+
+  _fpu.cpu(cpu)._fpsid = s;
+
   printf("FPU%d: Arch: %s(%lx), Part: %s(%lx), r: %lx, v: %lx, i: %lx, t: %s, p: %s\n",
          cpu, fpsid_arch_version(s) == 1
            ? "VFPv2"
@@ -260,52 +283,6 @@ Fpu::is_enabled()
   return fpexc() & FPEXC_EN;
 }
 
-PRIVATE static inline NEEDS[Fpu::fpexc, "processor.h", "trap_state.h"]
-bool
-Fpu::is_fpu_trap(Trap_state *ts, Mword *opcode)
-{
-  if (ts->psr & Proc::Status_thumb)
-    {
-      Unsigned16 *insn = reinterpret_cast<Unsigned16*>(ts->ip()) - 1;
-
-      if ((*insn & 0xe000) == 0xe000 && (*insn & 0x1800))
-       *opcode = (Mword(*insn) << 16) | *(insn + 1);
-      else
-       return false;
-    }
-  else
-    *opcode = *(reinterpret_cast<Mword*>(ts->ip()) - 1);
-
-  if ((*opcode & 0xec000000) == 0xec000000
-      && (((*opcode & 0x00000f00) == 0x00000a00)
-          || ((*opcode & 0x00000f00) == 0x00000b00)))
-    return true;
-
-  return false;
-}
-
-PUBLIC static
-Fpu::Fpu_exception_returns
-Fpu::handle_fpu_trap(Trap_state *ts)
-{
-  Mword opcode;
-  if (Fpu::is_fpu_trap(ts, &opcode))
-    {
-      if (Fpu::is_enabled())
-       {
-         if ((opcode & 0x0fff0f90) == 0x0ef00a10)
-           {
-             unsigned reg = (opcode >> 12) & 0xf;
-             ts->r[reg] = Fpu::fpsid();
-             return Fpu_except_emulated;
-           }
-       }
-      return Fpu_except_fault;
-    }
-
-  return Fpu_except_none;
-}
-
 PUBLIC static inline NEEDS["trap_state.h"]
 void
 Fpu::save_user_exception_state(Trap_state *ts, Exception_state_user *esu)
index 83d28f46c3f50e33425aa3631e21f3e351f359fb..07f7a4ba927916b0f16aad801c84937101901523 100644 (file)
@@ -325,7 +325,7 @@ prefetch_abort: @ A real prefetch abort occured --- handled as a page fault
        mrc     p15, 0, r1, c5, c0, 1   @ Load IFSR into r1
        bic     r1, r1, #0x00ff0000
        orr     r1, r1, #0x00330000     @ Set read bit and prefetch abort
-#if defined(CONFIG_ARM_V6PLUS) && !defined(CONFIG_ARM_1136)
+#if defined(CONFIG_ARM_V6PLUS) && !defined(CONFIG_ARM_1136) && !defined(CONFIG_ARM_MPCORE)
        mrc     p15, 0, r0, c6, c0, 2   @ Read fault address, for T2: pfa != pc
 #else
        ldr     r0, [sp, #RF(PC, 5*4)]  @ Get PC from RF and use as pfa
index 5d118ccd3476005b78a8217270cdbad830c0ed56..1953cb62ddf4b87c1193119e1dfceabdd15cedc4 100644 (file)
@@ -468,10 +468,30 @@ public:
   enum { Have_asids = 0 };
 };
 
+//----------------------------------------------------------------------------
+IMPLEMENTATION [armv6 || armca8]:
+
+PRIVATE inline static
+unsigned long
+Mem_space::next_asid(unsigned cpu)
+{
+  return _next_free_asid.cpu(cpu)++;
+}
 
 //----------------------------------------------------------------------------
-IMPLEMENTATION [armv6 || armv7]:
+IMPLEMENTATION [armv7 && armca9]:
+
+PRIVATE inline static
+unsigned long
+Mem_space::next_asid(unsigned cpu)
+{
+  if (_next_free_asid.cpu(cpu) == 0)
+    ++_next_free_asid.cpu(cpu);
+  return _next_free_asid.cpu(cpu)++;
+}
 
+//----------------------------------------------------------------------------
+IMPLEMENTATION [armv6 || armv7]:
 
 Per_cpu<unsigned char>    DEFINE_PER_CPU Mem_space::_next_free_asid;
 Per_cpu<Mem_space *[256]> DEFINE_PER_CPU Mem_space::_active_asids;
@@ -489,11 +509,6 @@ unsigned long
 Mem_space::c_asid() const
 { return _asid[current_cpu()]; }
 
-PRIVATE inline static
-unsigned long
-Mem_space::next_asid(unsigned cpu)
-{ return _next_free_asid.cpu(cpu)++; }
-
 PRIVATE inline NEEDS[Mem_space::next_asid]
 unsigned long
 Mem_space::asid()
@@ -526,7 +541,7 @@ Mem_space::asid()
       _asid[cpu] = new_asid;
     }
 
-  //LOG_MSG_3VAL(current(), "ASID", (Mword)this, _asid, (Mword)__builtin_return_address(0));
+  //LOG_MSG_3VAL(current(), "ASID", (Mword)this, _asid[cpu], (Mword)__builtin_return_address(0));
   return _asid[cpu];
 };
 
diff --git a/kernel/fiasco/src/kern/arm/outer_cache-l2cxx0.cpp b/kernel/fiasco/src/kern/arm/outer_cache-l2cxx0.cpp
new file mode 100644 (file)
index 0000000..4161afc
--- /dev/null
@@ -0,0 +1,203 @@
+INTERFACE [arm && outer_cache_l2cxx0]:
+
+#include "mem_layout.h"
+#include "spin_lock.h"
+
+EXTENSION class Outer_cache
+{
+private:
+  enum
+  {
+    Cache_line_shift = 5,
+
+    CACHE_ID                       = Mem_layout::L2cxx0_map_base + 0x000,
+    CACHE_TYPE                     = Mem_layout::L2cxx0_map_base + 0x004,
+    CONTROL                        = Mem_layout::L2cxx0_map_base + 0x100,
+    AUX_CONTROL                    = Mem_layout::L2cxx0_map_base + 0x104,
+    TAG_RAM_CONTROL                = Mem_layout::L2cxx0_map_base + 0x108,
+    DATA_RAM_CONTROL               = Mem_layout::L2cxx0_map_base + 0x10c,
+    EVENT_COUNTER_CONTROL          = Mem_layout::L2cxx0_map_base + 0x200,
+    EVENT_COUTNER1_CONFIG          = Mem_layout::L2cxx0_map_base + 0x204,
+    EVENT_COUNTER0_CONFIG          = Mem_layout::L2cxx0_map_base + 0x208,
+    EVENT_COUNTER1_VALUE           = Mem_layout::L2cxx0_map_base + 0x20c,
+    EVENT_COUNTER0_VALUE           = Mem_layout::L2cxx0_map_base + 0x210,
+    INTERRUPT_MASK                 = Mem_layout::L2cxx0_map_base + 0x214,
+    MASKED_INTERRUPT_STATUS        = Mem_layout::L2cxx0_map_base + 0x218,
+    RAW_INTERRUPT_STATUS           = Mem_layout::L2cxx0_map_base + 0x21c,
+    INTERRUPT_CLEAR                = Mem_layout::L2cxx0_map_base + 0x220,
+    CACHE_SYNC                     = Mem_layout::L2cxx0_map_base + 0x730,
+    INVALIDATE_LINE_BY_PA          = Mem_layout::L2cxx0_map_base + 0x770,
+    INVALIDATE_BY_WAY              = Mem_layout::L2cxx0_map_base + 0x77c,
+    CLEAN_LINE_BY_PA               = Mem_layout::L2cxx0_map_base + 0x7b0,
+    CLEAN_LINE_BY_INDEXWAY         = Mem_layout::L2cxx0_map_base + 0x7bb,
+    CLEAN_BY_WAY                   = Mem_layout::L2cxx0_map_base + 0x7bc,
+    CLEAN_AND_INV_LINE_BY_PA       = Mem_layout::L2cxx0_map_base + 0x7f0,
+    CLEAN_AND_INV_LINE_BY_INDEXWAY = Mem_layout::L2cxx0_map_base + 0x7f8,
+    CLEAN_AND_INV_BY_WAY           = Mem_layout::L2cxx0_map_base + 0x7fc,
+    LOCKDOWN_BY_WAY_D_SIDE         = Mem_layout::L2cxx0_map_base + 0x900,
+    LOCKDOWN_BY_WAY_I_SIDE         = Mem_layout::L2cxx0_map_base + 0x904,
+    TEST_OPERATION                 = Mem_layout::L2cxx0_map_base + 0xf00,
+    LINE_TAG                       = Mem_layout::L2cxx0_map_base + 0xf30,
+    DEBUG_CONTROL_REGISTER         = Mem_layout::L2cxx0_map_base + 0xf40,
+  };
+
+  static Spin_lock<> _lock;
+
+  static void platform_init();
+
+public:
+  enum
+  {
+    Cache_line_size = 1 << Cache_line_shift,
+    Cache_line_mask = Cache_line_size - 1,
+  };
+};
+
+// ------------------------------------------------------------------------
+IMPLEMENTATION [arm && outer_cache_l2cxx0]:
+
+#include "io.h"
+#include "static_init.h"
+#include "lock_guard.h"
+
+Spin_lock<> Outer_cache::_lock;
+
+IMPLEMENT inline NEEDS ["io.h"]
+void
+Outer_cache::sync()
+{
+  while (Io::read<Mword>(CACHE_SYNC))
+    ;
+}
+
+PRIVATE static inline NEEDS ["io.h", "lock_guard.h"]
+void
+Outer_cache::write(Address reg, Mword val)
+{
+  Lock_guard<Spin_lock<> > guard(&_lock);
+  Io::write<Mword>(val, reg);
+  while (Io::read<Mword>(reg) & 1)
+    ;
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::clean()
+{
+  write(CLEAN_BY_WAY, 0xff);
+  sync();
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::clean(Mword phys_addr, bool do_sync = true)
+{
+  write(CLEAN_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
+  if (do_sync)
+    sync();
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::flush()
+{
+  write(CLEAN_BY_WAY, 0xff);
+  sync();
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::flush(Mword phys_addr, bool do_sync = true)
+{
+  write(CLEAN_AND_INV_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
+  if (do_sync)
+    sync();
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::invalidate()
+{
+  write(INVALIDATE_BY_WAY, 0xff);
+  sync();
+}
+
+IMPLEMENT inline NEEDS[Outer_cache::write]
+void
+Outer_cache::invalidate(Address phys_addr, bool do_sync = true)
+{
+  write(INVALIDATE_LINE_BY_PA, phys_addr & (~0UL << Cache_line_shift));
+  if (do_sync)
+    sync();
+}
+
+PUBLIC static
+void
+Outer_cache::init()
+{
+  // disable
+  Io::write(0, CONTROL);
+
+  platform_init();
+
+  Io::write<Mword>(0, INTERRUPT_MASK);
+
+  invalidate();
+  Io::write<Mword>(~0UL, INTERRUPT_CLEAR);
+
+  // enable
+  Io::write(1, CONTROL);
+
+  show_info();
+}
+
+STATIC_INITIALIZE_P(Outer_cache, STARTUP_INIT_PRIO);
+
+// ------------------------------------------------------------------------
+IMPLEMENTATION [arm && outer_cache_l2cxx0 && !debug]:
+
+PRIVATE static
+void
+Outer_cache::show_info()
+{}
+
+// ------------------------------------------------------------------------
+IMPLEMENTATION [arm && outer_cache_l2cxx0 && debug]:
+
+#include "io.h"
+#include <cstdio>
+
+PRIVATE static
+void
+Outer_cache::show_info()
+{
+  const char *type;
+  Mword cache_id   = Io::read<Mword>(CACHE_ID);
+  Mword aux        = Io::read<Mword>(AUX_CONTROL);
+  unsigned ways    = 8;
+  unsigned waysize = 16 << (((aux >> 17) & 7) - 1);
+
+  printf("L2: ID=%08lx Type=%08lx Aux=%08lx\n",
+         cache_id, Io::read<Mword>(CACHE_TYPE), aux);
+
+  switch ((cache_id >> 6) & 0xf)
+    {
+    case 1:
+      type = "210";
+      ways = (aux >> 13) & 0xf;
+      break;
+    case 2:
+      type = "220";
+      ways = (aux >> 13) & 0xf;
+      break;
+    case 3:
+      type = "310";
+      ways = aux & (1 << 16) ? 16 : 8;
+      break;
+    default:
+      type = "Unknown";
+      break;
+    }
+
+  printf("L2: Type L2C-%s Size = %dkB\n", type, ways * waysize);
+}
index 0a34306b4e29fd712252579247180e0742f61924..9783d0d13da46e552275b97227045376c0b3fb5e 100644 (file)
@@ -87,9 +87,9 @@ public:
   {
     Ttbr_bits =    (1 << 1)            // S, Shareable bit
                 |  (1 << 3)            // RGN, Region bits, Outer WriteBackWriteAlloc
-               |  (0 << 0) | (1 << 6) // IRGN, Inner region bits, WB-WA
-               |  (1 << 5)            // NOS
-               ,
+                |  (0 << 0) | (1 << 6) // IRGN, Inner region bits, WB-WA
+                |  (1 << 5)            // NOS
+                ,
   };
 };
 
@@ -370,15 +370,15 @@ void Page_table::activate()
       _current.cpu(current_cpu()) = this;
       Mem_unit::flush_vcache();
       asm volatile (
-         "mcr p15, 0, r0, c8, c7, 0x00 \n" // TLB flush
-         "mcr p15, 0, %0, c2, c0       \n" // pdbr
-
-         "mrc p15, 0, r1, c2, c0       \n"
-         "mov r1, r1                   \n"
-         "sub pc, pc, #4               \n"
-         :
-         : "r"(p.phys(this))
-         : "r1" );
+          "mcr p15, 0, r0, c8, c7, 0 \n" // TLB flush
+          "mcr p15, 0, %0, c2, c0    \n" // pdbr
+
+          "mrc p15, 0, r1, c2, c0    \n"
+          "mov r1, r1                \n"
+          "sub pc, pc, #4            \n"
+          :
+          : "r" (p.phys(this))
+          : "r1");
     }
 }
 
@@ -462,7 +462,10 @@ Pte::attr(Mem_page_attr const &attr, bool write_back)
     }
 }
 
-PUBLIC /*inline*/
+//-----------------------------------------------------------------------------
+IMPLEMENTATION [armv6 || armca8]:
+
+PUBLIC
 void Page_table::activate(unsigned long asid)
 {
   Pte p = walk(this, 0, false, 0);
@@ -471,17 +474,47 @@ void Page_table::activate(unsigned long asid)
       _current.cpu(current_cpu()) = this;
       asm volatile (
           "mcr p15, 0, %2, c7, c5, 6    \n" // bt flush
-         "mcr p15, 0, r0, c7, c10, 4   \n"
-         "mcr p15, 0, %0, c2, c0       \n" // pdbr
-         "mcr p15, 0, %1, c13, c0, 1   \n"
+          "mcr p15, 0, r0, c7, c10, 4   \n" // dsb
+          "mcr p15, 0, %0, c2, c0       \n" // set TTBR
+          "mcr p15, 0, r0, c7, c10, 4   \n" // dsb
+          "mcr p15, 0, %1, c13, c0, 1   \n" // set new ASID value
+          "mcr p15, 0, r0, c7, c5, 4    \n" // isb
+          "mcr p15, 0, %2, c7, c5, 6    \n" // bt flush
+          "mrc p15, 0, r1, c2, c0       \n"
+          "mov r1, r1                   \n"
+          "sub pc, pc, #4               \n"
+          :
+          : "r" (p.phys(this) | Ttbr_bits), "r"(asid), "r" (0)
+          : "r1");
+    }
+}
 
-         "mrc p15, 0, r1, c2, c0       \n"
-         "mov r1, r1                   \n"
-         "sub pc, pc, #4               \n"
+//-----------------------------------------------------------------------------
+IMPLEMENTATION [armv7 && armca9]:
 
-         :
-         : "r" (p.phys(this) | Ttbr_bits), "r"(asid), "r" (0)
-         : "r1");
+PUBLIC
+void Page_table::activate(unsigned long asid)
+{
+  Pte p = walk(this, 0, false, 0);
+  if (_current.cpu(current_cpu()) != this)
+    {
+      _current.cpu(current_cpu()) = this;
+      asm volatile (
+          "mcr p15, 0, %2, c7, c5, 6    \n" // bt flush
+          "dsb                          \n"
+          "mcr p15, 0, %2, c13, c0, 1   \n" // change ASID to 0
+          "isb                          \n"
+          "mcr p15, 0, %0, c2, c0       \n" // set TTBR
+          "isb                          \n"
+          "mcr p15, 0, %1, c13, c0, 1   \n" // set new ASID value
+          "isb                          \n"
+          "mcr p15, 0, %2, c7, c5, 6    \n" // bt flush
+          "isb                          \n"
+          "mov r1, r1                   \n"
+          "sub pc, pc, #4               \n"
+          :
+          : "r" (p.phys(this) | Ttbr_bits), "r"(asid), "r" (0)
+          : "r1");
     }
 }
 
@@ -542,16 +575,14 @@ void Page_table::operator delete(void *b)
 IMPLEMENT
 Page_table::Page_table()
 {
-  for( unsigned i = 0; i< 4096; ++i )
-    raw[i]=0;
+  Mem::memset_mwords(raw, 0, sizeof(raw) / sizeof(Mword));
   if (Pte::need_cache_clean())
-    Mem_unit::clean_dcache(raw, raw + 4096);
+    Mem_unit::clean_dcache(raw, (char *)raw + sizeof(raw));
 }
 
 PUBLIC
 void Page_table::free_page_tables(void *start, void *end)
 {
-
   for (unsigned i = (Address)start >> 20; i < ((Address)end >> 20); ++i)
     {
       Pte p(this, 0, raw + i);
index e414eae682a1d714c281302526a265794700dfcf..b61c5c2443ae3a94d0b1161630d741f0568fa8ba 100644 (file)
@@ -39,17 +39,18 @@ void
 Sys_call_page::init()
 {
   Mword *sys_calls = (Mword*)Mem_layout::Syscalls;
-  if (!Vmem_alloc::page_alloc(sys_calls, 
-       Vmem_alloc::NO_ZERO_FILL, Vmem_alloc::User))
+  if (!Vmem_alloc::page_alloc(sys_calls,
+                              Vmem_alloc::NO_ZERO_FILL, Vmem_alloc::User))
     panic("FIASCO: can't allocate system-call page.\n");
 
   for (unsigned i = 0; i < Config::PAGE_SIZE; i += sizeof(Mword))
-    *(sys_calls++) = 0xef000000; // swi
+    *(sys_calls++) = 0xef000000; // svc
 
   set_utcb_get_code((Mword*)(Mem_layout::Syscalls + 0xf00));
 
-  Kernel_task::kernel_task()->mem_space()->set_attributes(Mem_layout::Syscalls,
-      Mem_space::Page_cacheable | Mem_space::Page_user_accessible);
+  Kernel_task::kernel_task()->mem_space()
+      ->set_attributes(Mem_layout::Syscalls,
+                       Mem_space::Page_cacheable | Mem_space::Page_user_accessible);
 
+  Mem_unit::flush_cache();
 }
-
index d4e18d8cd593f3236850e6eee5f9d10630390500..79297460c1fb0f78e7d35c2ffa854938481135f7 100644 (file)
@@ -127,6 +127,8 @@ bool Thread::handle_sigma0_page_fault( Address pfa )
       != Mem_space::Insert_err_nomem);
 }
 
+typedef bool (*Undef_coprop_insn_handler)(Unsigned32 opcode, Trap_state *ts);
+static Undef_coprop_insn_handler handle_copro_fault[16];
 
 extern "C" {
 
@@ -236,30 +238,29 @@ extern "C" {
 
     if (ts->exception_is_undef_insn())
       {
-       switch (Fpu::handle_fpu_trap(ts))
+       Unsigned32 opcode;
+
+       if (ts->psr & Proc::Status_thumb)
          {
-           case Fpu::Fpu_except_emulated: return;
-            case Fpu::Fpu_except_fault:
-#ifndef NDEBUG
-                  if (!(current_thread()->state() & Thread_vcpu_enabled)
-                      && Fpu::is_enabled() && Fpu::owner(t->cpu()) == t)
-                    printf("KERNEL: FPU doesn't like us?\n");
-                  else
-#endif
-                 if (t->switchin_fpu())
-                    {
-                      ts->pc -= (ts->psr & Proc::Status_thumb) ? 2 : 4;
-                      return;
-                    }
-
-                  ts->error_code |= 0x01000000; // tag fpu undef insn
-                  if (Fpu::exc_pending())
-                    ts->error_code |= 0x02000000; // fpinst and fpinst2 in utcb will be valid
-                  break;
-            case Fpu::Fpu_except_none: break;
+           Unsigned16 v = *(Unsigned16 *)(ts->pc - 2);
+           if ((v >> 11) <= 0x1c)
+             goto undef_insn;
+
+           opcode = (v << 16) | *(Unsigned16 *)ts->pc;
          }
+       else
+         opcode = *(Unsigned32 *)(ts->pc - 4);
+
+        if ((opcode & 0x0c000000) == 0x0c000000)
+          {
+            unsigned copro = (opcode >> 8) & 0xf;
+            if (   handle_copro_fault[copro]
+                && handle_copro_fault[copro](opcode, ts))
+              return;
+          }
       }
 
+undef_insn:
     // send exception IPC if requested
     if (t->send_exception(ts))
       return;
@@ -519,6 +520,35 @@ Thread::sys_control_arch(Utcb *)
   return 0;
 }
 
+PUBLIC static inline
+bool
+Thread::condition_valid(Unsigned32 insn, Unsigned32 psr)
+{
+  // Matrix of instruction conditions and PSR flags,
+  // index into the table is the condition from insn
+  Unsigned16 v[16] =
+  {
+    0xf0f0,
+    0x0f0f,
+    0xcccc,
+    0x3333,
+    0xff00,
+    0x00ff,
+    0xaaaa,
+    0x5555,
+    0x0c0c,
+    0xf3f3,
+    0xaa55,
+    0x55aa,
+    0x0a05,
+    0xf5fa,
+    0xffff,
+    0xffff
+  };
+
+  return (v[insn >> 28] >> (psr >> 28)) & 1;
+}
+
 // ------------------------------------------------------------------------
 IMPLEMENTATION [arm && armv6plus]:
 
@@ -583,3 +613,53 @@ PUBLIC static inline
 bool
 Thread::check_for_ipi(unsigned)
 { return false; }
+
+//-----------------------------------------------------------------------------
+IMPLEMENTATION [arm && fpu]:
+
+PUBLIC static
+bool
+Thread::handle_fpu_trap(Unsigned32 opcode, Trap_state *ts)
+{
+  if (!condition_valid(opcode, ts->psr))
+    {
+      if (ts->psr & Proc::Status_thumb)
+        ts->pc += 2;
+      return true;
+    }
+
+  if (Fpu::is_enabled())
+    if ((opcode & 0x0ff00f90) == 0x0ef00a10)
+      return Fpu::emulate_insns(opcode, ts, current_cpu());
+
+#ifndef NDEBUG
+  Thread *t = current_thread();
+  if (!(t->state() & Thread_vcpu_enabled)
+      && Fpu::is_enabled() && Fpu::owner(t->cpu()) == t)
+    printf("KERNEL: FPU doesn't like us?\n");
+  else
+#endif
+    if (current_thread()->switchin_fpu())
+      {
+        if ((opcode & 0x0ff00f90) == 0x0ef00a10)
+          return Fpu::emulate_insns(opcode, ts, current_cpu());
+        ts->pc -= (ts->psr & Proc::Status_thumb) ? 2 : 4;
+        return true;
+      }
+
+  ts->error_code |= 0x01000000; // tag fpu undef insn
+  if (Fpu::exc_pending())
+    ts->error_code |= 0x02000000; // fpinst and fpinst2 in utcb will be valid
+
+  return false;
+}
+
+PUBLIC static
+void
+Thread::init_fpu_trap_handling()
+{
+  handle_copro_fault[10] = Thread::handle_fpu_trap;
+  handle_copro_fault[11] = Thread::handle_fpu_trap;
+}
+
+STATIC_INITIALIZEX(Thread, init_fpu_trap_handling);
index c9bbfb752e2c5f5af36ebd3ac6935974b6cfae7c..f400dc84471eb502373bb72effb370902376b086 100644 (file)
@@ -62,13 +62,15 @@ _tramp_mp_entry:
        mcr   p15, 0, r0, c7, c7, 0  // inv both
 #endif
 
+#ifdef CONFIG_ARM_V7
        // ACTRL is implementation defined
        mrc   p15, 0, r0, c0, c0, 0  // read MIDR
-       adr   r3, .Lactrl_cpuid      // load addr
+       adr   r3, .Lactrl_cpuid_a9   // load addr
        ldm   r3, {r1,r2}            // load mask + val
        and   r0, r1                 // apply mask
        teq   r0, r2                 // check value
        bne   2f                     // only do mcr on this CPU
+#endif
 
        mrc   p15, 0, r0, c1, c0, 1
 #ifdef CONFIG_ARM_V7
@@ -113,7 +115,7 @@ _tramp_mp_entry:
        .long MPCORE_PHYS_BASE
 
 // only one currently
-.Lactrl_cpuid:
+.Lactrl_cpuid_a9:
          .long 0xff0ffff0
          .long 0x410fc090
 
index 9d575805f50dd7fc04bbc01d9e142cdbce933bff..9fbc2e785a2033ace2a6bc36f2c17ca8d948c156 100644 (file)
@@ -234,7 +234,7 @@ bool Config::profiling = false;
 unsigned Config::tbuf_entries = 0x20000 / sizeof(Mword); //1024;
 
 //-----------------------------------------------------------------------------
-IMPLEMENTATION [!arm && !ppc32]:
+IMPLEMENTATION:
 
 IMPLEMENT FIASCO_INIT
 void Config::init()
index 40cadbf3ca49ebc17bdd6c92dea290dda3448f0c..517ba532beb857c35941f1e68023b2b2b0976d35 100644 (file)
@@ -1,61 +1,20 @@
 INTERFACE:
 
+#include "bitmap.h"
+#include "config.h"
+
 class Cpu_mask
 {
 public:
-  Cpu_mask() : _m(0) {}
+  Cpu_mask() { _b.clear_all(); }
 
-  bool empty() const;
-  bool get(unsigned cpu) const;
-  void clear(unsigned cpu);
-  void set(unsigned cpu);
-  bool atomic_get_and_clear(unsigned cpu);
+  bool empty() const { return _b.is_empty(); }
+  bool get(unsigned cpu) const { return _b[cpu]; }
+  void clear(unsigned cpu) { return _b.clear_bit(cpu); }
+  void set(unsigned cpu) { _b.set_bit(cpu); };
+  bool atomic_get_and_clear(unsigned cpu)
+  { return _b.atomic_get_and_clear(cpu); }
 
 private:
-  // currently up to MWORD_BITS cpus are supported by this mask
-  unsigned long _m;
+  Bitmap<Config::Max_num_cpus> _b;
 };
-
-
-//---------------------------------------------------------------------------
-IMPLEMENTATION:
-
-#include <atomic.h>
-
-IMPLEMENT inline
-bool
-Cpu_mask::empty() const
-{ return !_m; }
-
-
-IMPLEMENT inline
-bool
-Cpu_mask::get(unsigned cpu) const
-{ return _m & (1UL << cpu); }
-
-
-IMPLEMENT inline
-void
-Cpu_mask::clear(unsigned cpu)
-{ _m = (_m & ~(1UL << cpu)); }
-
-
-IMPLEMENT inline
-void
-Cpu_mask::set(unsigned cpu)
-{ _m |= 1UL << cpu; }
-
-IMPLEMENT inline NEEDS [<atomic.h>]
-bool
-Cpu_mask::atomic_get_and_clear(unsigned cpu)
-{
-  unsigned long v;
-  do
-    {
-      v = _m;
-    }
-  while (!mp_cas(&_m, v, v & ~(1UL << cpu)));
-
-  return v & (1UL << cpu);
-}
-
index 7fb89c0ad823b43ff7574e9d0f92d3a2d7277a2e..0288ddfdd82b9090753e152b8052ca3b370b6689 100644 (file)
@@ -57,6 +57,9 @@ Dirq_io_apic::Chip::setup(Irq_base *irq, unsigned irqnum)
   unsigned apic_idx = Io_apic::find_apic(irqnum);
   irqnum -= Io_apic::apic(apic_idx)->gsi_offset();
 
+  if (irqnum >= Io_apic::apic(apic_idx)->nr_irqs())
+    return; // Hm, do we need an error code here?
+
   //irq->pin()->set_mode(Default_mode);
   if (irq->pin()->get_mode() & Irq::Trigger_level)
     irq->pin()->replace<Pin_io_apic_level>(apic_idx, irqnum);
@@ -68,14 +71,15 @@ IMPLEMENT
 bool
 Dirq_io_apic::Chip::alloc(Irq_base *irq, unsigned irqnum)
 {
-  if (!Dirq_pic_pin::Chip::alloc(irq, irqnum))
-    return false;
-
-
   unsigned apic_idx = Io_apic::find_apic(irqnum);
   Io_apic *a = Io_apic::apic(apic_idx);
   unsigned lirqn = irqnum - a->gsi_offset();
 
+  if (lirqn >= a->nr_irqs())
+    return false;
+
+  if (!Dirq_pic_pin::Chip::alloc(irq, irqnum))
+    return false;
 
   Io_apic_entry e = a->read_entry(lirqn);
   e.vector(vector(irqnum));
index 6caf09e8954adf6318b6b8b5d26b8c404e47ace8..280892a1ca99f5e6ad7737cdfc3e89504afa9f32 100644 (file)
@@ -34,32 +34,40 @@ public:
   static void enable();
 
 private:
+  Context *_owner;
 
-  static Per_cpu<Context *>_owner;
+  static Per_cpu<Fpu> _fpu;
 };
 
 IMPLEMENTATION:
 
 #include "fpu_state.h"
 
-Per_cpu<Context *> DEFINE_PER_CPU Fpu::_owner;
+Per_cpu<Fpu> DEFINE_PER_CPU Fpu::_fpu;
 
 IMPLEMENT inline
 Context * Fpu::owner(unsigned cpu)
 {
-  return _owner.cpu(cpu);
+  return _fpu.cpu(cpu)._owner;
 }
 
 IMPLEMENT inline
 void Fpu::set_owner(unsigned cpu, Context *owner)
 {
-  _owner.cpu(cpu) = owner;
+  _fpu.cpu(cpu)._owner = owner;
 }
 
 IMPLEMENT inline
 bool Fpu::is_owner(unsigned cpu, Context *owner)
 {
-  return _owner.cpu(cpu) == owner;
+  return _fpu.cpu(cpu)._owner == owner;
+}
+
+PUBLIC static inline
+Fpu &
+Fpu::fpu(unsigned cpu)
+{
+  return _fpu.cpu(cpu);
 }
 
 //---------------------------------------------------------------------------
index d64430d80d0a0e312f9bef242d4e77cbcbb62efb..0caed34b94cecc7badbbffa20a84fe6d9a971fcd 100644 (file)
@@ -6,6 +6,7 @@
 INTERFACE[ia32,ux]:
 
 #include "initcalls.h"
+#include "std_macros.h"
 
 class Kernel_thread;
 
index 27f4e49c56b363f58c276f2e7e80ba31dedcd039..cab8b8dc98fe0647ed6a9cbc38d63c805d55f410 100644 (file)
@@ -6,6 +6,7 @@
 INTERFACE[amd64]:
 
 #include "initcalls.h"
+#include "std_macros.h"
 
 class Kernel_thread;
 
index 501ea102a93d9e1700adf8852a3234864bdee23c..535c15e6e286c6804a20786fa43032ccfaeeefb5 100644 (file)
@@ -103,7 +103,7 @@ IMPLEMENTATION[(ia32,amd64) && mp]:
 
 int FIASCO_FASTCALL boot_ap_cpu(unsigned _cpu) __asm__("BOOT_AP_CPU");
 
-int boot_ap_cpu(unsigned _cpu)
+int FIASCO_FASTCALL boot_ap_cpu(unsigned _cpu)
 {
   if (!Per_cpu_data_alloc::alloc(_cpu))
     {
index 88ffe683ec2ebcebec1453991fc1978e59c1f55e..8b3d3ab85fc70001cf990fbb0daf979f183ba07f 100644 (file)
@@ -58,6 +58,7 @@ private:
   Apic *_apic;
   Spin_lock<> _l;
   unsigned _offset;
+  unsigned _irqs;
 
   static Io_apic _apics[Max_ioapics];
   static unsigned _nr_irqs;
@@ -179,11 +180,12 @@ Io_apic::init()
       Io_apic *apic = Io_apic::apic(n_apics);
       apic->_apic = (Io_apic::Apic*)(va + offs);
       apic->write(0, 0);
-      unsigned ne = apic->num_entries();
-      apic->_offset = _nr_irqs;
-      _nr_irqs += ne + 1;
+      apic->_irqs = apic->num_entries() + 1;
+      apic->_offset = ioapic->irq_base;
+      if ((apic->_offset + apic->_irqs) > _nr_irqs)
+       _nr_irqs = apic->_offset + apic->_irqs;
 
-      for (unsigned i = 0; i <= ne; ++i)
+      for (unsigned i = 0; i < apic->_irqs; ++i)
         {
           int v = 0x20+i;
           Io_apic_entry e(v, Io_apic_entry::Fixed, Io_apic_entry::Physical,
@@ -191,7 +193,7 @@ Io_apic::init()
           apic->write_entry(i, e);
         }
 
-      printf("IO-APIC[%2d]: pins %u\n", n_apics, ne);
+      printf("IO-APIC[%2d]: pins %u\n", n_apics, apic->_irqs);
       apic->dump();
     }
 
@@ -223,7 +225,7 @@ unsigned
 Io_apic::total_irqs()
 { return _nr_irqs; }
 
-PUBLIC static 
+PUBLIC static
 unsigned
 Io_apic::legacy_override(unsigned i)
 {
@@ -249,8 +251,7 @@ PUBLIC
 void
 Io_apic::dump()
 {
-  unsigned ne = num_entries();
-  for (unsigned i = 0; i <= ne; ++i)
+  for (unsigned i = 0; i < _irqs; ++i)
     {
       Io_apic_entry e = read_entry(i);
       printf("  PIN[%2u%c]: vector=%2x, del=%u, dm=%s, dest=%u (%s, %s)\n",
@@ -311,10 +312,10 @@ Io_apic::set_dest(unsigned irq, Mword dst)
   modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
 }
 
-PUBLIC inline NEEDS[Io_apic::num_entries]
+PUBLIC inline
 unsigned
 Io_apic::nr_irqs()
-{ return num_entries() + 1; }
+{ return _irqs; }
 
 PUBLIC inline
 unsigned
@@ -331,7 +332,7 @@ Io_apic::find_apic(unsigned irqnum)
 {
   for (unsigned i = Max_ioapics; i > 0; --i)
     {
-      if (_apics[i-1]._apic && _apics[i-1]._offset < irqnum)
+      if (_apics[i-1]._apic && _apics[i-1]._offset <= irqnum)
        return i - 1;
     }
   return 0;
index b5bd9607eb7a45ca689a1e42033da8494bb281ae..b1d68835f4a37ab7b1aa30fed6158b80627915d2 100644 (file)
@@ -32,8 +32,8 @@ Mem_space_sigma0::v_fabricate(Vaddr address,
                               unsigned* attribs = 0)
 {
   // special-cased because we don't do ptab lookup for sigma0
-  *phys = address.trunc(Size(Config::SUPERPAGE_SIZE));
-  *size = Size(Config::SUPERPAGE_SIZE);
+  *size = has_superpages() ? Size(Config::SUPERPAGE_SIZE) : Size(Config::PAGE_SIZE);
+  *phys = address.trunc(*size);
 
   if (attribs)
     *attribs = Page_writable | Page_user_accessible | Page_cacheable;
index 447a18cf073ec0d2ad06d1598212d88017bd1d89..b0e68f6b844c72beca89f85719a4e964abff599f 100644 (file)
@@ -59,19 +59,8 @@ IMPLEMENTATION [ppc32]:
 
 char const Config::char_micro = '\265';
 const char *const Config::kernel_warn_config_string = 0;
-//static int Config::serial_esc;
-//---------------------------------------------------------------------------
-IMPLEMENTATION [ppc32 & serial]:
-
-IMPLEMENT FIASCO_INIT
-void Config::init()
-{
-  serial_esc = SERIAL_ESC_IRQ;
-}
-
-//---------------------------------------------------------------------------
-IMPLEMENTATION [ppc32 & !serial]:
 
 IMPLEMENT FIASCO_INIT
-void Config::init()
+void
+Config::init_arch()
 {}
index 9c672e05912db5c865e07223b16fae5678a6e191..ee308d1a6981c5b1f0e86e9cacbcc8122dc175e1 100644 (file)
@@ -87,7 +87,7 @@ static char const * const __tag_interpreter_strings_fiasco[] = {
     "Kpreempt",
     "Ksysexc",
     "Kexc",      // -5
-    "Ks0",
+    "Ksigma",
     0,
     "Kiopf",
     "Kcapfault",
index 306ef65ed267c8428c3ae25460ef3c5dbd7ad7bd..1d1890d51ea9db2acca43a11935ed8906bf6a270 100644 (file)
@@ -117,7 +117,8 @@ Thread::ipc_receiver_aborted()
   receiver()->vcpu_update_state();
   set_receiver(0);
 
-  remote_ready_enqueue();
+  // remote_ready_enqueue(): is only for mp
+  activate();
 }
 
 PUBLIC inline
@@ -768,6 +769,7 @@ Thread::send_exception(Trap_state *ts)
                 l->cap_idx = _exc_handler.raw());
       if (EXPECT_FALSE(space() == sigma0_task))
        {
+         ts->dump();
          WARNX(Error, "Sigma0 raised an exception --> HALT\n");
          panic("...");
        }
index b207545f43cbfa39a8d07742261594b56ead469e..aa8e9460b79d7adfe88a15b87c77a4a5fb6c6d24 100644 (file)
@@ -80,9 +80,6 @@ Thread_object::put()
 
 
 
-/** Deallocator.  This function currently does nothing: We do not free up
-    space allocated to thread-control blocks.
- */
 PUBLIC
 void
 Thread_object::operator delete(void *_t)
@@ -107,7 +104,6 @@ Thread_object::destroy(Kobject ***rl)
   Kobject::destroy(rl);
   check_kdb(kill());
   assert_kdb(_magic == magic);
-
 }
 
 PUBLIC
index 7f847de65684bb4bf4f9a0108868241ef34b3bdf..7432728839e1f4f8f9b7c935d2d052f3e29f990b 100644 (file)
 INTERFACE:
 
-class Bitmap_base
+#include "atomic.h"
+
+template< bool LARGE >
+class Bitmap_base;
+
+// Implementation for bitmaps bigger than sizeof(unsigned long) * 8
+// Derived classes have to make sure to provide the storage space for
+// holding the bitmap.
+template<>
+class Bitmap_base< true >
 {
+public:
+  void bit(unsigned long bit, bool on)
+  {
+    unsigned long idx = bit / Bpl;
+    unsigned long b   = bit % Bpl;
+    _bits()[idx] = (_bits()[idx] & ~(1UL << b)) | ((unsigned long)on << b);
+  }
+
+  void clear_bit(unsigned long bit)
+  {
+    unsigned long idx = bit / Bpl;
+    unsigned long b   = bit % Bpl;
+    _bits()[idx] &= ~(1UL << b);
+  }
+
+  void set_bit(unsigned long bit)
+  {
+    unsigned long idx = bit / Bpl;
+    unsigned long b   = bit % Bpl;
+    _bits()[idx] |= (1UL << b);
+  }
+
+  unsigned long operator [] (unsigned long bit) const
+  {
+    unsigned long idx = bit / Bpl;
+    unsigned long b   = bit % Bpl;
+    return _bits()[idx] & (1UL << b);
+  }
+
+  bool atomic_get_and_clear(unsigned long bit)
+  {
+    unsigned long idx = bit / Bpl;
+    unsigned long b   = bit % Bpl;
+    unsigned long v;
+    do
+      {
+        v = _bits()[idx];
+      }
+    while (!mp_cas(&_bits()[idx], v, v & ~(1UL << b)));
+
+    return v & (1UL << b);
+  }
+
+protected:
+  enum
+  {
+    Bpl      = sizeof(unsigned long) * 8,
+  };
+
+  Bitmap_base() {}
+
 private:
-  unsigned long _bits[0];
+  unsigned long *_bits()
+  { return reinterpret_cast<unsigned long *>(this); }
+
+  unsigned long const *_bits() const
+  { return reinterpret_cast<unsigned long const *>(this); }
 };
 
-template<int BITS>
-class Bitmap : public Bitmap_base
+// Implementation for a bitmap up to sizeof(unsigned long) * 8 bits
+template<>
+class Bitmap_base<false>
 {
-private:
-  char _bits[(BITS+7)/8];
-};
+public:
+  void bit(unsigned long bit, bool on)
+  {
+    _bits[0] = (_bits[0] & ~(1UL << bit)) | ((unsigned long)on << bit);
+  }
 
+  void clear_bit(unsigned long bit)
+  {
+    _bits[0] &= ~(1UL << bit);
+  }
 
-IMPLEMENTATION:
+  void set_bit(unsigned long bit)
+  {
+    _bits[0] |= 1UL << bit;
+  }
 
+  unsigned long operator [] (unsigned long bit) const
+  {
+    return _bits[0] & (1UL << bit);
+  }
 
-PUBLIC inline
-void
-Bitmap_base::bit(unsigned long bit, bool on)
-{
-  unsigned long idx = bit / (sizeof(unsigned long) * 8);
-  unsigned long b   = bit % (sizeof(unsigned long) * 8);
-  _bits[idx] = (_bits[idx] & ~(1UL << b)) | ((unsigned long)on << b);
-}
-
-PUBLIC inline
-void
-Bitmap_base::clear_bit(unsigned long bit)
-{
-  unsigned long idx = bit / (sizeof(unsigned long) * 8);
-  unsigned long b   = bit % (sizeof(unsigned long) * 8);
-  _bits[idx] &= ~(1UL << b);
-}
-
-PUBLIC inline
-void
-Bitmap_base::set_bit(unsigned long bit)
-{
-  unsigned long idx = bit / (sizeof(unsigned long) * 8);
-  unsigned long b   = bit % (sizeof(unsigned long) * 8);
-  _bits[idx] |= (1UL << b);
-}
-
-PUBLIC inline
-unsigned long
-Bitmap_base::operator [] (unsigned long bit) const
+  bool atomic_get_and_clear(unsigned long bit)
+  {
+    unsigned long v;
+    do
+      {
+        v = _bits[0];
+      }
+    while (!mp_cas(&_bits[0], v, v & ~(1UL << bit)));
+
+    return v & (1UL << bit);
+  }
+
+protected:
+  enum
+  {
+    Bpl      = sizeof(unsigned long) * 8,
+  };
+  unsigned long _bits[1];
+};
+
+template<int BITS>
+class Bitmap : public Bitmap_base< (BITS > sizeof(unsigned long) * 8) >
 {
-  unsigned long idx = bit / (sizeof(unsigned long) * 8);
-  unsigned long b   = bit % (sizeof(unsigned long) * 8);
-  return _bits[idx] & (1UL << b);
-}
+public:
+  void clear_all()
+  {
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      _bits[i] = 0;
+  }
 
+  bool is_empty() const
+  {
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      if (_bits[i])
+       return false;
+    return true;
+  }
+
+private:
+  enum {
+    Bpl      = sizeof(unsigned long) * 8,
+    Nr_elems = (BITS + Bpl - 1) / Bpl,
+  };
+  unsigned long _bits[Nr_elems];
+};
index 873105fe9b9b9864397e8e18ce88fe16a201a350..3276f61a39fca4698fb898544df778b59279a459 100644 (file)
@@ -30,6 +30,7 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 # CONFIG_ARM_1176 is not set
 # CONFIG_ARM_MPCORE is not set
@@ -38,6 +39,7 @@ CONFIG_ARM_CORTEX_A9=y
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
 # CONFIG_ARM_TZ is not set
 CONFIG_ARM_CA9_ENABLE_SWP=y
+CONFIG_ARM_CACHE_L2CXX0=y
 CONFIG_FPU=y
 
 #
index 72bfe71e13dd2a5bcf529e57dbc39f197bdd92fd..ac51b5e51277dbafafb17e23d51eb03270562ac8 100644 (file)
@@ -30,6 +30,7 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 # CONFIG_ARM_1176 is not set
 # CONFIG_ARM_MPCORE is not set
@@ -38,6 +39,7 @@ CONFIG_ARM_CORTEX_A9=y
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
 CONFIG_ARM_TZ=y
 # CONFIG_ARM_CA9_ENABLE_SWP is not set
+# CONFIG_ARM_CACHE_L2CXX0 is not set
 CONFIG_FPU=y
 
 #
index a3040a43fc12477fa211fe6b6c9e1d1e741b92aa..8c39a502dc6dc490e10bf3f89a045fb3ad4a54f2 100644 (file)
@@ -29,12 +29,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 CONFIG_ARM_926=y
 # CONFIG_ARM_1176 is not set
 # CONFIG_ARM_MPCORE is not set
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 # CONFIG_FPU is not set
 
 #
index 0ca6d193a0c0de6e698e1b6e26ae9255b29269a0..18a438322a002088b9047e1990157e74ff177473 100644 (file)
@@ -29,12 +29,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 CONFIG_ARM_1176=y
 # CONFIG_ARM_MPCORE is not set
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+# CONFIG_ARM_CACHE_L2CXX0 is not set
 # CONFIG_FPU is not set
 CONFIG_ARM_1176_CACHE_ALIAS_FIX=y
 
index 5b12a803d72907cf9b5176a79add8f60d5ace6b2..4986468a2a12b2d0fbe1c6c9de749c385ada518d 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_PF_REALVIEW_EB=y
 # CONFIG_PF_REALVIEW_PBX is not set
 # CONFIG_PF_REALVIEW_VEXPRESS is not set
 CONFIG_PF_REALVIEW_RAM_PHYS_BASE=0x0
-# CONFIG_PF_REALVIEW_L2CACHE is not set
 CONFIG_ABI_VF=y
 CONFIG_PF_ARM_MP_CAPABLE=y
 CONFIG_CAN_ARM_CPU_926=y
@@ -31,12 +30,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 # CONFIG_ARM_1176 is not set
 CONFIG_ARM_MPCORE=y
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 # CONFIG_FPU is not set
 
 #
index 68e8db99c36f4b21aa49dae69e35c52c0ea89ba5..cdcb935ce54d5cdf9d49ef0caa6cc885a9794c7f 100644 (file)
@@ -29,12 +29,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 CONFIG_ARM_926=y
 # CONFIG_ARM_1176 is not set
 # CONFIG_ARM_MPCORE is not set
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 # CONFIG_FPU is not set
 
 #
index ab946acc257b54a3ed1580f249a9eb98d1b10442..b41ff90812e1813d06da82f75bd4182c8925b40e 100644 (file)
@@ -21,10 +21,12 @@ CONFIG_BSP_NAME="tegra2"
 CONFIG_ABI_VF=y
 CONFIG_PF_ARM_MP_CAPABLE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 CONFIG_ARM_CORTEX_A9=y
 CONFIG_ARM_ALIGNMENT_CHECK=y
 CONFIG_ARM_TZ=y
 CONFIG_ARM_CA9_ENABLE_SWP=y
+CONFIG_ARM_CACHE_L2CXX0=y
 CONFIG_FPU=y
 
 #
index 4c5dd197688140b63e7d48bb7bb754c9a76042c2..712aad13fa71b3e02a1d76b0ab31475d3fcbb7cd 100644 (file)
@@ -29,12 +29,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 CONFIG_ARM_1176=y
 # CONFIG_ARM_MPCORE is not set
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+# CONFIG_ARM_CACHE_L2CXX0 is not set
 # CONFIG_FPU is not set
 CONFIG_ARM_1176_CACHE_ALIAS_FIX=y
 
index 7fd2652f369598a4221396098b9d39a7ac7c4720..336e9877727ade43b6576b85b5ec89aa7ee41b31 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_PF_REALVIEW_EB=y
 # CONFIG_PF_REALVIEW_PBX is not set
 # CONFIG_PF_REALVIEW_VEXPRESS is not set
 CONFIG_PF_REALVIEW_RAM_PHYS_BASE=0x0
-CONFIG_PF_REALVIEW_L2CACHE=y
 CONFIG_ABI_VF=y
 CONFIG_PF_ARM_MP_CAPABLE=y
 CONFIG_CAN_ARM_CPU_926=y
@@ -31,12 +30,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 # CONFIG_ARM_1176 is not set
 CONFIG_ARM_MPCORE=y
 # CONFIG_ARM_CORTEX_A8 is not set
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 CONFIG_FPU=y
 
 #
index aac4cf355cec3ae458178029bc6fb27f1c71f0db..be22674a8fbf0a9d2ff8922c28e35ddf921eedb6 100644 (file)
@@ -25,12 +25,13 @@ CONFIG_PF_REALVIEW_PB11MP=y
 CONFIG_PF_REALVIEW_RAM_PHYS_BASE_0x0=y
 # CONFIG_PF_REALVIEW_RAM_PHYS_BASE_0x7 is not set
 CONFIG_PF_REALVIEW_RAM_PHYS_BASE=0x0
-CONFIG_PF_REALVIEW_L2CACHE=y
 CONFIG_ABI_VF=y
 CONFIG_PF_ARM_MP_CAPABLE=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 CONFIG_ARM_MPCORE=y
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 CONFIG_FPU=y
 
 #
index 8ada38a4d108890296962363acc14b9d847acf98..2b4b9b51337a9e482e6fbd6e19650cdf76951279 100644 (file)
@@ -29,12 +29,14 @@ CONFIG_CAN_ARM_CPU_1176=y
 CONFIG_CAN_ARM_CPU_MPCORE=y
 CONFIG_CAN_ARM_CPU_CORTEX_A8=y
 CONFIG_CAN_ARM_CPU_CORTEX_A9=y
+CONFIG_CAN_ARM_CACHE_L2CXX0=y
 # CONFIG_ARM_926 is not set
 # CONFIG_ARM_1176 is not set
 # CONFIG_ARM_MPCORE is not set
 CONFIG_ARM_CORTEX_A8=y
 # CONFIG_ARM_CORTEX_A9 is not set
 # CONFIG_ARM_ALIGNMENT_CHECK is not set
+CONFIG_ARM_CACHE_L2CXX0=y
 # CONFIG_FPU is not set
 
 #
index 3e3d9b84f5b064e29ad36792de6c74e377f3e945..78f6afc10d20ffcacccf1960db33aa487f8db2d1 100644 (file)
@@ -1,8 +1,8 @@
-VERSION = 2
-PATCHLEVEL = 6
-SUBLEVEL = 39
+VERSION = 3
+PATCHLEVEL = 0
+SUBLEVEL = 0
 EXTRAVERSION =
-NAME = Flesh-Eating Bats with Fangs
+NAME = Sneaky Weasel
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -103,7 +103,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 ifeq ("$(origin W)", "command line")
-  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
 endif
 
 # That's our default target when none is given on the command line
@@ -220,6 +220,14 @@ ifeq ($(ARCH),sh64)
        SRCARCH := sh
 endif
 
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+       SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+       SRCARCH := tile
+endif
+
 # Where to locate arch specific headers
 hdr-arch  := $(SRCARCH)
 
@@ -349,7 +357,8 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
+                   -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
                    -include include/generated/autoconf.h
 
@@ -369,7 +378,7 @@ KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
 KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
-KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
 
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
@@ -382,6 +391,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+export KBUILD_ARFLAGS
 
 # When compiling out-of-tree modules, put MODVERDIR in the module
 # tree rather than in the kernel tree. The kernel tree might
@@ -416,6 +426,12 @@ ifneq ($(KBUILD_SRC_disabled_for_fiasco),)
            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
 endif
 
+# Support for using generic headers in asm-generic
+PHONY += asm-generic
+asm-generic:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
+                   obj=arch/$(SRCARCH)/include/generated/asm
+
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
 # It is allowed to specify more targets when calling make, including
@@ -559,6 +575,10 @@ ifndef CONFIG_CC_STACKPROTECTOR
 KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
 endif
 
+# This warning generated too much noise in a regular build.
+# Use make W=1 to enable this warning (see scripts/Makefile.build)
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -604,7 +624,7 @@ CHECKFLAGS     += $(NOSTDINC_FLAGS)
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
 # disable pointer signed / unsigned warnings in gcc 4.0
-KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
@@ -612,6 +632,9 @@ KBUILD_CFLAGS       += $(call cc-option,-fno-strict-overflow)
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
+# use the deterministic mode of AR if available
+KBUILD_ARFLAGS := $(call ar-option,D)
+
 # check for 'asm goto'
 ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
@@ -797,15 +820,17 @@ ifdef CONFIG_KALLSYMS
 # o The correct .tmp_kallsyms2.o is linked into the final vmlinux.
 # o Verify that the System.map from vmlinux matches the map from
 #   .tmp_vmlinux2, just in case we did not generate kallsyms correctly.
-# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# o If 'make KALLSYMS_EXTRA_PASS=1" was used, do an extra pass using
 #   .tmp_vmlinux3 and .tmp_kallsyms3.o.  This is only meant as a
 #   temporary bypass to allow the kernel to be built while the
 #   maintainers work out what went wrong with kallsyms.
 
-ifdef CONFIG_KALLSYMS_EXTRA_PASS
-last_kallsyms := 3
-else
 last_kallsyms := 2
+
+ifdef KALLSYMS_EXTRA_PASS
+ifneq ($(KALLSYMS_EXTRA_PASS),0)
+last_kallsyms := 3
+endif
 endif
 
 kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
@@ -816,7 +841,8 @@ define verify_kallsyms
          $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
        $(Q)cmp -s System.map .tmp_System.map ||                             \
                (echo Inconsistent kallsyms data;                            \
-                echo Try setting CONFIG_KALLSYMS_EXTRA_PASS;                \
+                echo This is a bug - please report about it;                \
+                echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround;      \
                 rm .tmp_kallsyms* ; /bin/false )
 endef
 
@@ -947,7 +973,7 @@ ifneq ($(KBUILD_SRC),)
 endif
 
 # prepare2 creates a makefile if using a separate output directory
-prepare2: prepare3 outputmakefile
+prepare2: prepare3 outputmakefile asm-generic
 
 prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
                    include/config/auto.conf
@@ -979,7 +1005,7 @@ endef
 
 define filechk_version.h
        (echo \#define LINUX_VERSION_CODE $(shell                             \
-       expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL));     \
+       expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL));    \
        echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
 endef
 
@@ -991,7 +1017,8 @@ include/generated/utsrelease.h: include/config/kernel.release FORCE
 
 PHONY += headerdep
 headerdep:
-       $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+       $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
+       $(srctree)/scripts/headerdep.pl -I$(srctree)/include
 
 # ---------------------------------------------------------------------------
 
@@ -1021,7 +1048,7 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
 PHONY += __headers
-__headers: include/linux/version.h scripts_basic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic FORCE
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
@@ -1083,11 +1110,6 @@ modules_install: _modinst_ _modinst_post
 
 PHONY += _modinst_
 _modinst_:
-       @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
-               echo "Warning: you may need to install module-init-tools"; \
-               echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
-               sleep 1; \
-       fi
        @rm -rf $(MODLIB)/kernel
        @rm -f $(MODLIB)/source
        @mkdir -p $(MODLIB)/kernel
@@ -1136,7 +1158,8 @@ CLEAN_FILES +=    vmlinux System.map \
                 .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config usr/include include/generated
+MRPROPER_DIRS  += include/config usr/include include/generated          \
+                  arch/*/include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
@@ -1267,7 +1290,12 @@ help:
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
        @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
-       @echo  '  make W=1   [targets] Enable extra gcc checks'
+       @echo  '  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where'
+       @echo  '                1: warnings which may be relevant and do not occur too often'
+       @echo  '                2: warnings which occur quite often but may still be relevant'
+       @echo  '                3: more obscure warnings, can most likely be ignored'
+       @echo  '                Multiple levels can be combined with W=12 or W=123'
+       @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
        @echo  ''
        @echo  'Execute "make" or "make all" to build all targets marked with [*] '
        @echo  'For further info see the ./README file'
@@ -1290,6 +1318,7 @@ $(help-board-dirs): help-%:
 # Documentation targets
 # ---------------------------------------------------------------------------
 %docs: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts build_docproc
        $(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 else # KBUILD_EXTMOD
@@ -1374,7 +1403,7 @@ endif # KBUILD_EXTMOD
 clean: $(clean-dirs)
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
-       @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+       @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
                \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
@@ -1392,13 +1421,15 @@ tags TAGS cscope gtags: FORCE
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
 
+PHONY += includecheck versioncheck coccicheck namespacecheck export_report
+
 includecheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl
 
 versioncheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
 
@@ -1495,12 +1526,8 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files))
 
 # Run depmod only if we have System.map and depmod is executable
 quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
-      cmd_depmod = \
-       if [ -r System.map -a -x $(DEPMOD) ]; then                              \
-               $(DEPMOD) -ae -F System.map                                     \
-               $(if $(strip $(INSTALL_MOD_PATH)), -b $(INSTALL_MOD_PATH) )     \
-               $(KERNELRELEASE);                                               \
-       fi
+      cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
+                   $(KERNELRELEASE)
 
 # Create temporary dir for module support files
 # clean it up only when building all modules
index 778d26aeeb8df76a4780a4053f0ba8e65352e95c..8f797d724ef625f2c54176f3273daf462ab644ac 100644 (file)
@@ -1,3 +1,3 @@
 
-kconfig taken from vanilla Linux 2.6.39, and slightly patched.
+kconfig taken from vanilla Linux 3.0, and slightly patched.
 
index ed2773edfe71bae99adc0a7b64a454912dfd4477..be39cd1c74cff6009eac1120c1eafe18085ed37e 100644 (file)
@@ -118,6 +118,11 @@ cc-option-yn = $(call try-run,\
 cc-option-align = $(subst -functions=0,,\
        $(call cc-option,-falign-functions=0,-malign-functions=0))
 
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
 # cc-version
 # Usage gcc-ver := $(call cc-version)
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
@@ -141,6 +146,11 @@ cc-ldoption = $(call try-run,\
 ld-option = $(call try-run,\
        $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
 
+# ar-option
+# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
+# Important: no spaces around options
+ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+
 ######
 
 ###
@@ -187,6 +197,8 @@ ifneq ($(KBUILD_NOCMDDEP),1)
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+else
+arg-check = $(if $(strip $(cmd_$@)),,1)
 endif
 
 # >'< substitution is for echo to work,
index fcea26168bca718afb07cf4a2a71081b309e906e..df7678febf277b119cbffc4d3b6f230974fb18f0 100644 (file)
@@ -6,6 +6,7 @@
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
+# docproc:       Used in Documentation/DocBook
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
@@ -16,12 +17,14 @@ hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 always         := $(hostprogs-y) $(hostprogs-m)
 
 # The following hostprogs-y programs are only build on demand
-hostprogs-y += unifdef
+hostprogs-y += unifdef docproc
 
-# This target is used internally to avoid "is up to date" messages
+# These targets are used internally to avoid "is up to date" messages
 PHONY += build_unifdef
 build_unifdef: scripts/unifdef FORCE
        @:
+build_docproc: scripts/docproc FORCE
+       @:
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
index d5f925abe4d29710ab0b314bf28d29752b35dc8d..a0fd5029cfe78c8d082409b3228a59998b15eaa2 100644 (file)
@@ -51,36 +51,52 @@ ifeq ($(KBUILD_NOPEDANTIC),)
 endif
 
 #
-# make W=1 settings
+# make W=... settings
 #
-# $(call cc-option... ) handles gcc -W.. options which
+# W=1 - warnings that may be relevant and does not occur too often
+# W=2 - warnings that occur quite often but may still be relevant
+# W=3 - the more obscure warnings, can most likely be ignored
+#
+# $(call cc-option, -W...) handles gcc -W.. options which
 # are not supported by all versions of the compiler
 ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
-KBUILD_EXTRA_WARNINGS := -Wextra
-KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
-KBUILD_EXTRA_WARNINGS += -Waggregate-return
-KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
-KBUILD_EXTRA_WARNINGS += -Wcast-qual
-KBUILD_EXTRA_WARNINGS += -Wcast-align
-KBUILD_EXTRA_WARNINGS += -Wconversion
-KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
-KBUILD_EXTRA_WARNINGS += -Wlogical-op
-KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
-KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
-KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
-KBUILD_EXTRA_WARNINGS += -Wnested-externs
-KBUILD_EXTRA_WARNINGS += -Wold-style-definition
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
-KBUILD_EXTRA_WARNINGS += -Wpacked
-KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
-KBUILD_EXTRA_WARNINGS += -Wpadded
-KBUILD_EXTRA_WARNINGS += -Wpointer-arith
-KBUILD_EXTRA_WARNINGS += -Wredundant-decls
-KBUILD_EXTRA_WARNINGS += -Wshadow
-KBUILD_EXTRA_WARNINGS += -Wswitch-default
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
-KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
+warning-  := $(empty)
+
+warning-1 := -Wextra -Wunused -Wno-unused-parameter
+warning-1 += -Wmissing-declarations
+warning-1 += -Wmissing-format-attribute
+warning-1 += -Wmissing-prototypes
+warning-1 += -Wold-style-definition
+warning-1 += $(call cc-option, -Wmissing-include-dirs)
+warning-1 += $(call cc-option, -Wunused-but-set-variable)
+
+warning-2 := -Waggregate-return
+warning-2 += -Wcast-align
+warning-2 += -Wdisabled-optimization
+warning-2 += -Wnested-externs
+warning-2 += -Wshadow
+warning-2 += $(call cc-option, -Wlogical-op)
+
+warning-3 := -Wbad-function-cast
+warning-3 += -Wcast-qual
+warning-3 += -Wconversion
+warning-3 += -Wpacked
+warning-3 += -Wpadded
+warning-3 += -Wpointer-arith
+warning-3 += -Wredundant-decls
+warning-3 += -Wswitch-default
+warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
+warning-3 += $(call cc-option, -Wvla)
+
+warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+
+ifeq ("$(strip $(warning))","")
+        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
+endif
+
+KBUILD_CFLAGS += $(warning)
 endif
 
 include scripts/Makefile.lib
@@ -244,14 +260,19 @@ endif
 
 ifdef CONFIG_FTRACE_MCOUNT_RECORD
 ifdef BUILD_C_RECORDMCOUNT
+ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
+  RECORDMCOUNT_FLAGS = -w
+endif
 # Due to recursion, we must skip empty.o.
 # The empty.o file is created in the make process in order to determine
 #  the target endianness and word size. It is made before all other C
 #  files, including recordmcount.
 sub_cmd_record_mcount =                                        \
        if [ $(@) != "scripts/mod/empty.o" ]; then      \
-               $(objtree)/scripts/recordmcount "$(@)"; \
+               $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)";   \
        fi;
+recordmcount_source := $(srctree)/scripts/recordmcount.c \
+                   $(srctree)/scripts/recordmcount.h
 else
 sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
        "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
@@ -259,6 +280,7 @@ sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH
        "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
        "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
        "$(if $(part-of-module),1,0)" "$(@)";
+recordmcount_source := $(srctree)/scripts/recordmcount.pl
 endif
 cmd_record_mcount =                                            \
        if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then    \
@@ -279,13 +301,13 @@ define rule_cc_o_c
 endef
 
 # Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c FORCE
+$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
 
-$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
        @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
@@ -345,7 +367,7 @@ quiet_cmd_link_o_target = LD      $@
 cmd_link_o_target = $(if $(strip $(obj-y)),\
                      $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
                      $(cmd_secanalysis),\
-                     rm -f $@; $(AR) rcs $@)
+                     rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
 
 $(builtin-target): $(obj-y) FORCE
        $(call if_changed,link_o_target)
@@ -371,7 +393,7 @@ $(modorder-target): $(subdir-ym) FORCE
 #
 ifdef lib-target
 quiet_cmd_link_l_target = AR      $@
-cmd_link_l_target = rm -f $@; $(AR) rcs $@ $(lib-y)
+cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
 
 $(lib-target): $(lib-y) FORCE
        $(call if_changed,link_l_target)
index f89cb87f5c018f24b56e13201530df261379c230..a57f5bd5a13d5b8f14a90b03bf23115e925b4a0a 100644 (file)
@@ -27,8 +27,13 @@ header-y      := $(filter-out %/, $(header-y))
 install-file  := $(install)/.install
 check-file    := $(install)/.check
 
+# generic-y list all files an architecture uses from asm-generic
+# Use this to build a list of headers which require a wrapper
+wrapper-files := $(filter $(header-y), $(generic-y))
+
 # all headers files for this dir
-all-files     := $(header-y) $(objhdr-y)
+header-y      := $(filter-out $(generic-y), $(header-y))
+all-files     := $(header-y) $(objhdr-y) $(wrapper-files)
 input-files   := $(addprefix $(srctree)/$(obj)/,$(header-y)) \
                  $(addprefix $(objtree)/$(obj)/,$(objhdr-y))
 output-files  := $(addprefix $(install)/, $(all-files))
@@ -47,6 +52,9 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \
         $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \
+        for F in $(wrapper-files); do                                   \
+                echo "\#include <asm-generic/$$F>" > $(install)/$$F;    \
+        done;                                                           \
         touch $@
 
 quiet_cmd_remove = REMOVE  $(unwanted)
index 1c702ca8aac81d853ac19c204d126c30dff639cb..93b2b5938a2e9e714590ca9728ec53a39763db06 100644 (file)
@@ -197,7 +197,7 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 # ---------------------------------------------------------------------------
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
        (rm -f $@ ; false)
 
 # DTC
index 4c324a1f1e0efb8668b4d64e05b56e8e0f64f25b..4fcef87bb8759894435a395224c7d92cd7a14214 100644 (file)
@@ -7,9 +7,8 @@
 # .config is included by main Makefile.
 # ---------------------------------------------------------------------------
 # fixdep:       Used to generate dependency information during build process
-# docproc:      Used in Documentation/DocBook
 
-hostprogs-y    := fixdep docproc
+hostprogs-y    := fixdep
 always         := $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
index 368ae306aee45a42fbcee26274b491af512afbf0..faa9a4701b6f27259b9f0094aa9ee3584f237fe4 100644 (file)
@@ -77,14 +77,15 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
 # The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
        $(Q)echo "  GEN config"
-       $(Q)xgettext --default-domain=linux              \
-           --add-comments --keyword=_ --keyword=N_      \
-           --from-code=UTF-8                            \
-           --files-from=scripts/kconfig/POTFILES.in     \
+       $(Q)xgettext --default-domain=linux                         \
+           --add-comments --keyword=_ --keyword=N_                 \
+           --from-code=UTF-8                                       \
+           --files-from=$(srctree)/scripts/kconfig/POTFILES.in     \
+           --directory=$(srctree) --directory=$(objtree)           \
            --output $(obj)/config.pot
        $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
-       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
-       $(Q)(for i in `ls arch/*/Kconfig`;               \
+       $(Q)ln -fs Kconfig.x86 arch/um/Kconfig
+       $(Q)(for i in `ls $(srctree)/arch/*/Kconfig`;    \
            do                                           \
                echo "  GEN $$i";                        \
                $(obj)/kxgettext $$i                     \
@@ -92,7 +93,7 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
            done )
        $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
            --output $(obj)/linux.pot
-       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(srctree)/arch/um/Kconfig
        $(Q)rm -f $(obj)/config.pot
 
 PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
@@ -168,8 +169,11 @@ conf-objs  := conf.o  zconf.tab.o
 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
 
-hostprogs-y := conf qconf gconf kxgettext
+hostprogs-y := conf
 
 ifeq ($(MAKECMDGOALS),nconfig)
        hostprogs-y += nconf
@@ -179,6 +183,10 @@ ifeq ($(MAKECMDGOALS),menuconfig)
        hostprogs-y += mconf
 endif
 
+ifeq ($(MAKECMDGOALS),update-po-config)
+       hostprogs-y += kxgettext
+endif
+
 ifeq ($(MAKECMDGOALS),xconfig)
        qconf-target := 1
 endif
@@ -188,16 +196,15 @@ endif
 
 
 ifeq ($(qconf-target),1)
-qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
+       hostprogs-y += qconf
 endif
 
 ifeq ($(gconf-target),1)
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+       hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
-                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    += zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 
@@ -321,11 +328,12 @@ $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
 $(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
 
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
-       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+       $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+       $(obj)/gconf.glade
 
 ###
 # The following requires flex/bison/gperf
index 6364981e9819e833e14f4a09224559337614f489..f6b5d64005f753ed97d2f90de360c29d91725ab2 100644 (file)
@@ -560,8 +560,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       time_t now;
-       int use_timestamp = 1;
        char *env;
 
        dirname[0] = 0;
@@ -598,19 +596,11 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       time(&now);
-       env = getenv("KCONFIG_NOTIMESTAMP");
-       if (env && *env)
-               use_timestamp = 0;
-
        fprintf(out, _("#\n"
                       "# Automatically generated make config: don't edit\n"
                       "# %s\n"
-                      "%s%s"
                       "#\n"),
-                    rootmenu.prompt->text,
-                    use_timestamp ? "# " : "",
-                    use_timestamp ? ctime(&now) : "");
+                    rootmenu.prompt->text);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -784,7 +774,6 @@ int conf_write_autoconf(void)
        const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
-       time_t now;
        int i;
 
        sym_clear_all_valid();
@@ -811,22 +800,19 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       time(&now);
        fprintf(out, "#\n"
                     "# Automatically generated make config: don't edit\n"
                     "# %s\n"
-                    "# %s"
                     "#\n",
-                    rootmenu.prompt->text, ctime(&now));
+                    rootmenu.prompt->text);
        fprintf(tristate, "#\n"
                          "# Automatically generated - do not edit\n"
                          "\n");
        fprintf(out_h, "/*\n"
                       " * Automatically generated C config: don't edit\n"
                       " * %s\n"
-                      " * %s"
                       " */\n",
-                      rootmenu.prompt->text, ctime(&now));
+                      rootmenu.prompt->text);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
index 3d238db4976405fee6aa122c3582e4a717a25315..16bfae2d321742bd5bf06e0a17e3e6377b47ef71 100644 (file)
@@ -20,12 +20,8 @@ struct file {
        struct file *parent;
        const char *name;
        int lineno;
-       int flags;
 };
 
-#define FILE_BUSY              0x0001
-#define FILE_SCANNED           0x0002
-
 typedef enum tristate {
        no, mod, yes
 } tristate;
index 295e9c98ed1ea2cdab5b55c9e21f8992ef65c76b..a8000d779451986267224f3f6d51b10470961405 100644 (file)
@@ -253,7 +253,7 @@ void init_left_tree(void)
 
        gtk_tree_view_set_model(view, model1);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -298,7 +298,7 @@ void init_right_tree(void)
 
        gtk_tree_view_set_model(view, model2);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -756,7 +756,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = SINGLE_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        current = &rootmenu;
        display_tree_part();
@@ -782,7 +781,6 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = FULL_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        if (tree2)
                gtk_tree_store_clear(tree2);
@@ -1444,6 +1442,12 @@ static void display_tree(struct menu *menu)
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW))*/
+
+               /* Change paned position if the view is not in 'split mode' */
+               if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+                       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+               }
+
                if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW)) {
index 6eb039718259a38838268c7df29a2212cb265bed..d9182916f72494d3138a93a352f24a11ee3f06e7 100644 (file)
@@ -2363,11 +2363,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -2383,18 +2383,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -2404,8 +2411,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index db56377393d7922229562fa1ea767f3288424e25..488dd741078747132b08dc9afb33001f4a03db5a 100644 (file)
@@ -373,18 +373,18 @@ static void print_function_line(void)
        const int skip = 1;
 
        for (i = 0; i < function_keys_num; i++) {
-               wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+               (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
                mvwprintw(main_window, LINES-3, offset,
                                "%s",
                                function_keys[i].key_str);
-               wattrset(main_window, attributes[FUNCTION_TEXT]);
+               (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
                offset += strlen(function_keys[i].key_str);
                mvwprintw(main_window, LINES-3,
                                offset, "%s",
                                function_keys[i].func);
                offset += strlen(function_keys[i].func) + skip;
        }
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 }
 
 /* help */
@@ -953,16 +953,16 @@ static void show_menu(const char *prompt, const char *instructions,
        current_instructions = instructions;
 
        clear();
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
        print_in_middle(stdscr, 1, 0, COLS,
                        menu_backtitle,
                        attributes[MAIN_HEADING]);
 
-       wattrset(main_window, attributes[MAIN_MENU_BOX]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
        box(main_window, 0, 0);
-       wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
        mvwprintw(main_window, 0, 3, " %s ", prompt);
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 
        set_menu_items(curses_menu, curses_menu_items);
 
index 06dd2e33581de5de81863bd1b74b2fb7100af5ed..c2796b866f8f14a37453f409429b900e1f11ba44 100644 (file)
@@ -1489,8 +1489,7 @@ void ConfigMainWindow::saveConfigAs(void)
        QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
-       if (conf_write(QFile::encodeName(s)))
-               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+       saveConfig();
 }
 
 void ConfigMainWindow::searchConfig(void)
@@ -1643,7 +1642,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               conf_write(NULL);
+               saveConfig();
        case QMessageBox::No:
                e->accept();
                break;
index 3dbaec185cc486d183ed5ba87cfe848635e4b968..b22f884f90221650ed46ef4cf509bf6a3b33170e 100644 (file)
@@ -294,11 +294,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -314,18 +314,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -335,8 +342,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index 4c2eca205df2cc25716302da92e08dc447e7f789..e3b44b937928b70c0002a8ea0391454cd3e39a82 100644 (file)
@@ -160,12 +160,14 @@ generate_l4defs_files = \
 $(L4DEF_FILE_MK): $(BUILD_DIRS) $(DROPSCONF_CONFIG_MK) $(L4DIR)/mk/export_defs.inc
        $(call generate_l4defs_files,static)
        $(call generate_l4defs_files,shared)
+       $(call generate_l4defs_files,sharedlib)
 
 $(L4DEF_FILE_SH): $(L4DEF_FILE_MK)
 
 regen_l4defs:
        $(call generate_l4defs_files,static)
        $(call generate_l4defs_files,shared)
+       $(call generate_l4defs_files,sharedlib)
 
 .PHONY: l4defs regen_l4defs
 
@@ -205,11 +207,15 @@ ARCH = $(BUILD_ARCH)
 Makeconf.bid.local-helper:
        $(VERBOSE)echo BUILD_SYSTEMS="$(strip $(ARCH)_$(CPU)            \
                       $(ARCH)_$(CPU)-$(BUILD_ABI))" >> $(DROPSCONF_CONFIG_MK)
-       $(VERBOSE)$(foreach v, GCCLIBDIR GCCDIR GCCLIB GCCLIB_EH GCCVERSION \
+       $(VERBOSE)$(foreach v, GCCDIR GCCLIB GCCLIB_EH GCCVERSION \
                        GCCMAJORVERSION GCCMINORVERSION GCCSUBVERSION   \
                        GCCNOSTACKPROTOPT LDVERSION GCCSYSLIBDIRS,      \
                        echo $(v)=$(call $(v)_f,$(ARCH))                \
                        >>$(DROPSCONF_CONFIG_MK);)
+       $(VERBOSE)$(foreach v, crtbegin.o crtbeginS.o crtbeginT.o \
+                              crtendS.o crtend.o, \
+                       echo GCCLIB_FILE_$(v)=$(call GCCLIB_file_f,$(v))   \
+                       >>$(DROPSCONF_CONFIG_MK);)
        $(VERBOSE)$(foreach v, LD_GENDEP_PREFIX, echo $v=$($(v)) >>$(DROPSCONF_CONFIG_MK);)
        $(VERBOSE)echo "HOST_SYSTEM=$(HOST_SYSTEM)" >>$(DROPSCONF_CONFIG_MK)
        $(VERBOSE)echo "COLOR_TERMINAL=$(shell if [ $$(tput colors || echo -1) = '-1' ]; then echo n; else echo y; fi)" >>$(DROPSCONF_CONFIG_MK)
index 27efec173bfd378691d52a142acc0696f2ca6ebb..c0ea3e894324a22459c94a325d045d43bd8a57fd 100644 (file)
@@ -434,6 +434,15 @@ if PLATFORM_PPC_mpc5200
 config PPC_PLATFORM_TYPE
        string
        default "mpc5200"
+
+config RAM_BASE
+       hex
+       default 0x0
+
+config RAM_SIZE_MB
+       int "RAM-Memory available on the platform in MB"
+       default 64
+
 endif
 
 endmenu
@@ -449,10 +458,26 @@ config CPU
        string "Sparc CPU variant"
        default "v8"
 
+config PLATFORM_SPARC_leon3
+       def_bool y
+
+if PLATFORM_SPARC_leon3
+
 config SPARC_PLATFORM_TYPE
        string
        default "leon3"
 
+config RAM_BASE
+       hex
+       default 0x0
+
+config RAM_SIZE_MB
+       int "RAM-Memory available on the platform in MB"
+       default 64
+
+
+endif
+
 endif
 
 
index 2ed673f3c66c235e1d13569477e2f9c698533027..13f56a1c19dac3976090e7dc78d74b41eec9fd8e 100644 (file)
@@ -391,8 +391,8 @@ GCCMINORVERSION_f=$(shell $(CC) -dumpversion | sed -e 's/[^.]*\.\([^.]*\).*/\1/'
 GCCSUBVERSION_f        = $(shell $(CC) -dumpversion | sed -e 's/.*\.\(.*\)/\1/')
 LDVERSION_f     = $(shell $(LD) -v | sed -e 's/.* \([0-9]\)\.\([^. ]*\).*/\1\2/')
 GCCSYSLIBDIRS_f = $(shell LC_ALL=C $(CC) -print-search-dirs | sed '/^libraries:/{s/^libraries: /-L/;s/:/ -L/g;q;};d')
-GCCDIR_f       = $(shell LC_ALL=C $(CC) -print-search-dirs|sed -ne 's+^install: \(.*[^/][^/]*\)/+\1+p' )
-GCCLIBDIR_f    = $(shell LC_ALL=C $(CC) -print-file-name=)
+GCCDIR_f       = $(shell LC_ALL=C $(CC) -print-search-dirs | sed -ne 's+^install: \(.*[^/][^/]*\)/+\1+p' )
+GCCLIB_file_f   = $(shell LC_ALL=C $(CC) -print-file-name=$(1))
 GCCLIB_f       = $(shell $(CC) -print-libgcc-file-name)
 GCCLIB_EH_f    = $(filter /%,$(shell $(CC) -print-file-name=libgcc_eh.a))
 GCCINCDIR_f    = $(addprefix $(call GCCDIR_f),/include /include-fixed)
index 7134537eb867789f058af94532dd6805d474e653..23ec6bcf5b94987c18aaf8c3ec23c3dbf8578b21 100644 (file)
@@ -1,3 +1,3 @@
-stdlibs-all := l4sys l4re l4re-main l4re-util libc_be_l4refile libc_be_l4re cxx_io cxx_libc_io
+stdlibs-all := l4sys l4re l4re-util libc_be_l4refile libc_be_l4re
 stdlibs     := stdlibs-all libl4re-vfs
 stdlibs-sh  := stdlibs-all ldso libdl libc_support_misc libc_be_socket_noop
index 29ba12b620227be9f7dff364c0d64ebe9e7694f3..b95ffd4699733a935eadafae988b8755c53ac7a9 100644 (file)
@@ -11,6 +11,8 @@ CONFIG_BUILD_ARCH="ppc32"
 CONFIG_BUILD_ABI_l4f=y
 CONFIG_BUILD_ABI="l4f"
 CONFIG_CPU="603e"
+CONFIG_RAM_BASE=0x0
+CONFIG_RAM_SIZE_MB=64
 
 #
 # Platform
index 0ea75ecad09762652ac9cdd20427edf6200efc30..08e2d24bb340c8142c78a1768455e24389895df5 100644 (file)
@@ -11,6 +11,9 @@ CONFIG_BUILD_ARCH="sparc"
 CONFIG_BUILD_ABI_l4f=y
 CONFIG_BUILD_ABI="l4f"
 CONFIG_CPU="v8"
+CONFIG_RAM_BASE=0x0
+CONFIG_RAM_SIZE_MB=64
+CONFIG_PLATFORM_SPARC_leon3=y
 CONFIG_SPARC_PLATFORM_TYPE="leon3"
 # CONFIG_USE_DROPS_STDDIR is not set
 # CONFIG_USE_DICE is not set
index 5cff4b5964123220d2563d41b0b38cea084cfc01..b355fa914d15dc2f2744ad4dfdb5f7a2c77c95d1 100644 (file)
@@ -101,6 +101,7 @@ include $(L4DIR)/mk/prog.mk
 
 endif # called for static
 
+#   ----------------------------------------------------
 
 ifeq ($(CALLED_FOR),shared)
 
@@ -110,16 +111,12 @@ ifneq ($(SYSTEM),)
 
 L4_LDFLAGS_LD_SHARED  = $(filter-out -l%,$(BID_LDFLAGS_FOR_LINKING_LD))
 L4_LDFLAGS_GCC_SHARED = $(filter-out -l%,$(BID_LDFLAGS_FOR_LINKING_GCC))
-L4_CRT0_DYN           = $(CRT0_all_lib)
-L4_CRTN_DYN           = $(CRTN_all_lib)
 L4_LDS_so             = $(LDS_so)
 L4_LDS_dyn_bin        = $(LDS_dyn_bin)
 
 all::
        @$(call do_output_all,L4_LDFLAGS_LD_SHARED)
        @$(call do_output_all,L4_LDFLAGS_GCC_SHARED)
-       @$(call do_output_all,L4_CRT0_DYN)
-       @$(call do_output_all,L4_CRTN_DYN)
        @$(call do_output_all,L4_LDS_so)
        @$(call do_output_all,L4_LDS_dyn_bin)
 
@@ -130,3 +127,23 @@ endif
 include $(L4DIR)/mk/prog.mk
 
 endif # called for shared
+
+#   ----------------------------------------------------
+
+ifeq ($(CALLED_FOR),sharedlib)
+
+ifneq ($(SYSTEM),)
+
+L4_CRT0_SO = $(CRT0)
+L4_CRTN_SO = $(CRTN)
+
+all::
+       @$(call do_output_all,L4_CRT0_SO)
+       @$(call do_output_all,L4_CRTN_SO)
+else
+all::
+endif
+
+include $(L4DIR)/mk/lib.mk
+
+endif # called for sharedlib
index 4ef49b6d506a721f6d1c315bec3251295b8e9253..3042c761a7832f531a55ed2f8119df23fda94826 100644 (file)
@@ -8,22 +8,22 @@ ifneq ($(L4_MULTITHREADED),)
 endif
 
 ifneq ($(MODE_USE_C),)
-  $(error MODE_USE_C is obsolete, add and l4re_c and/or l4re_c-util to REQUIRES_LIBS as needed)
+  $(error MODE_USE_C is obsolete, add l4re_c and/or l4re_c-util to REQUIRES_LIBS as needed)
 endif
 
 ifeq ($(ARCH),sparc)
-CRTBEGIN_so       = $(GCCLIBDIR)/crtbegin.o
-CRTBEGIN_stat_bin = $(GCCLIBDIR)/crtbegin.o
+CRTBEGIN_so       = $(GCCLIB_FILE_crtbegin.o)
+CRTBEGIN_stat_bin = $(GCCLIB_FILE_crtbegin.o)
 else
-CRTBEGIN_so       = $(GCCLIBDIR)/crtbeginS.o
-CRTBEGIN_stat_bin = $(GCCLIBDIR)/crtbeginT.o
+CRTBEGIN_so       = $(GCCLIB_FILE_crtbeginS.o)
+CRTBEGIN_stat_bin = $(GCCLIB_FILE_crtbeginT.o)
 endif
 
-CRTBEGIN_dyn_bin  = $(GCCLIBDIR)/crtbegin.o
+CRTBEGIN_dyn_bin  = $(GCCLIB_FILE_crtbegin.o)
 
-CRTEND_so         = $(GCCLIBDIR)/crtendS.o
-CRTEND_dyn_bin    = $(GCCLIBDIR)/crtend.o
-CRTEND_stat_bin   = $(GCCLIBDIR)/crtend.o
+CRTEND_so         = $(GCCLIB_FILE_crtendS.o)
+CRTEND_dyn_bin    = $(GCCLIB_FILE_crtend.o)
+CRTEND_stat_bin   = $(GCCLIB_FILE_crtend.o)
 
 
 CRT1_so           =
@@ -110,9 +110,7 @@ LDFLAGS_all_shared              = --eh-frame-hdr
 BID_SUPPORTED_all_l4linux       = y
 LIBCINCDIR_all_l4linux          =
 REQUIRES_LIBS_all_l4linux       = 
-L4_LIBS_all_l4linux            = -l4re_main                        \
-                                 $(L4_LIBS_all_l4linux_USE_C-y)    \
-                                  -l4re-util                        \
+L4_LIBS_all_l4linux            = -l4re-util                        \
                                   -l4lx-re.o                        \
                                  -ll4sys-l4x -l4re                 \
                                  $(EXTRA_LIBS)                     \
index a715590d2ecff318fd40abe56df5908cd1da95c6..fd998870b7c56af8630298e44ac4254d0c9e86ef 100644 (file)
@@ -2,7 +2,6 @@
 #include <l4/re/namespace>
 #include <l4/re/util/cap_alloc>
 #include <l4/cxx/ipc_stream>
-#include <l4/cxx/iostream>
 #include <l4/ankh/protocol>
 #include <l4/ankh/shm>
 #include <l4/ankh/session>
@@ -68,7 +67,7 @@ static void ankh_activate()
                assert(false);
        }
 
-       L4::Ipc_iostream s(l4_utcb());
+       L4::Ipc::Iostream s(l4_utcb());
 
        s << l4_umword_t(Ankh::Opcode::Activate);
        
index 8a4edf39de04afe8f39254b262a7ebb9d08f0f57..faafb8e481eaf30c6c9f5630876cc3cbef109e04 100644 (file)
@@ -2,7 +2,6 @@
 #include <l4/re/namespace>
 #include <l4/re/util/cap_alloc>
 #include <l4/cxx/ipc_stream>
-#include <l4/cxx/iostream>
 #include <l4/ankh/protocol>
 #include <l4/ankh/shm>
 #include <l4/ankh/session>
@@ -88,7 +87,7 @@ static void ankh_activate()
                assert(false);
        }
 
-       L4::Ipc_iostream s(l4_utcb());
+       L4::Ipc::Iostream s(l4_utcb());
 
        s << l4_umword_t(Ankh::Opcode::Activate);
 
index 1cb38f16bfe6c8830e1a782aa82bba259ad14634..10e5355a0a53d0b50bb22dafa811f430b4c7667a 100644 (file)
@@ -68,7 +68,7 @@ l4ankh_open(char *shm_name, int bufsize) L4_NOTHROW
        if (err)
                return err;
 
-       L4::Ipc_iostream s(l4_utcb());
+       L4::Ipc::Iostream s(l4_utcb());
        s << l4_umword_t(Ankh::Opcode::Activate);
        l4_msgtag_t res = s.call(ankh_server.cap(), Ankh::Protocol::Ankh);
        if (res.has_error())
index 54a7c8a49a7ced6f2aebdfdb7efa385351ceb069..14882bf293ba14105c44e40ea3f30043cab2cb98 100644 (file)
@@ -1 +1,3 @@
-lwip 1.3.1
+lwip git master
+commit 17efa04ea686f81ebdbf51363bdec5886e03a51c
+Date:   Tue Aug 9 13:55:40 2011 -0600
index 0d264af47fc29963af6a1fff38b312612c2a89e3..33f1399a1924c0e54010eb706a523d5f69eeda8e 100644 (file)
@@ -7,7 +7,8 @@ REQUIRES_LIBS    = ankh libpthread
 SYSTEMS          = x86-l4f arm-l4f
 CONTRIB_INCDIR   = ankh_lwip \
                    ankh_lwip/contrib/src/include \
-                   ankh_lwip/contrib/src/include/ipv4
+                   ankh_lwip/contrib/src/include/ipv4 \
+                   ankh_lwip/contrib/src/include/ipv6
 
 SRC_C  = arch/sys_arch.c \
                  arch/perf.c \
@@ -16,6 +17,7 @@ SRC_C = arch/sys_arch.c \
                  contrib/src/core/dhcp.c \
                  contrib/src/core/init.c \
                  contrib/src/core/dns.c \
+                 contrib/src/core/inet_chksum.c \
                  contrib/src/core/mem.c \
                  contrib/src/core/memp.c \
                  contrib/src/core/netif.c \
@@ -40,10 +42,8 @@ SRC_C        = arch/sys_arch.c \
                  contrib/src/core/ipv4/autoip.c \
                  contrib/src/core/ipv4/icmp.c \
                  contrib/src/core/ipv4/igmp.c \
-                 contrib/src/core/ipv4/inet.c \
-                 contrib/src/core/ipv4/inet_chksum.c \
-                 contrib/src/core/ipv4/ip_addr.c \
-                 contrib/src/core/ipv4/ip.c \
+                 contrib/src/core/ipv4/ip4_addr.c \
+                 contrib/src/core/ipv4/ip4.c \
                  contrib/src/core/ipv4/ip_frag.c \
                  contrib/src/core/snmp/asn1_dec.c \
                  contrib/src/core/snmp/asn1_enc.c \
index 15bb471de251c210ff9ba6ba871282ca5e057d7e..1444f2fc1c4fd8a7570aea76aa837c93951fed89 100644 (file)
@@ -96,11 +96,11 @@ static void *ankhif_recv_fn(void *arg)
 
     for (;;)
     {
-        err = l4shmc_rb_receiver_wait_for_data(rb, 0);
-        if (!err)
-            ankhif_input(netif);
-        else
-            l4_thread_yield();
+        err = l4shmc_rb_receiver_wait_for_data(rb, 1);
+               if (err) {
+                       continue;
+               }
+               ankhif_input(netif);
     }
 
     enter_kdebug("exit loop?");
@@ -298,6 +298,7 @@ ankhif_input(struct netif *netif)
   struct ankhif *ankhif;
   struct eth_hdr *ethhdr;
   struct pbuf *p;
+  int x;
 
   ankhif = netif->state;
 
@@ -318,7 +319,8 @@ ankhif_input(struct netif *netif)
   case ETHTYPE_PPPOE:
 #endif /* PPPOE_SUPPORT */
     /* full packet send to tcpip_thread to process */
-    if (netif->input(p, netif)!=ERR_OK)
+       x = netif->input(p, netif);
+    if (x!=ERR_OK)
      { LWIP_DEBUGF(NETIF_DEBUG, ("ankhif_input: IP input error\n"));
        pbuf_free(p);
        p = NULL;
@@ -326,6 +328,7 @@ ankhif_input(struct netif *netif)
     break;
 
   default:
+       printf("unknown ethtype %lx\n", htons(ethhdr->type));
     pbuf_free(p);
     p = NULL;
     break;
index a2f57f1fc3c66c77f69d7ed26924cc5a1e9c9ed9..f7375b0f1e49404b0b008c1b77da74910ca5e63c 100644 (file)
@@ -143,7 +143,7 @@ netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
 
   msg.function = do_getaddr;
   msg.msg.conn = conn;
-  msg.msg.msg.ad.ipaddr = addr;
+  msg.msg.msg.ad.ipaddr = ip_2_ipX(addr);
   msg.msg.msg.ad.port = port;
   msg.msg.msg.ad.local = local;
   err = TCPIP_APIMSG(&msg);
@@ -240,6 +240,7 @@ netconn_disconnect(struct netconn *conn)
 err_t
 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
 {
+#if LWIP_TCP
   struct api_msg msg;
   err_t err;
 
@@ -257,6 +258,11 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
 
   NETCONN_SET_SAFE_ERR(conn, err);
   return err;
+#else /* LWIP_TCP */
+  LWIP_UNUSED_ARG(conn);
+  LWIP_UNUSED_ARG(backlog);
+  return ERR_ARG;
+#endif /* LWIP_TCP */
 }
 
 /**
@@ -297,20 +303,20 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
 #else
   sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
 #endif /* LWIP_SO_RCVTIMEO*/
-    /* Register event with callback */
-    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
+  /* Register event with callback */
+  API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
 
   if (newconn == NULL) {
-    /* connection has been closed */
-    NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
-    return ERR_CLSD;
+    /* connection has been aborted */
+    NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
+    return ERR_ABRT;
   }
 #if TCP_LISTEN_BACKLOG
-      /* Let the stack know that we have accepted the connection. */
-      msg.function = do_recv;
-      msg.msg.conn = conn;
+  /* Let the stack know that we have accepted the connection. */
+  msg.function = do_recv;
+  msg.msg.conn = conn;
   /* don't care for the return value of do_recv */
-      TCPIP_APIMSG(&msg);
+  TCPIP_APIMSG(&msg);
 #endif /* TCP_LISTEN_BACKLOG */
 
   *new_conn = newconn;
@@ -366,7 +372,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
 #endif /* LWIP_SO_RCVTIMEO*/
 
 #if LWIP_TCP
-  if (conn->type == NETCONN_TCP) {
+  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
     if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
       /* Let the stack know that we have taken the data. */
       /* TODO: Speedup: Don't block and wait for the answer here
@@ -390,7 +396,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
       return ERR_CLSD;
     }
     len = ((struct pbuf *)buf)->tot_len;
-    }
+  }
 #endif /* LWIP_TCP */
 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
   else
@@ -399,12 +405,14 @@ netconn_recv_data(struct netconn *conn, void **new_buf)
   {
     LWIP_ASSERT("buf != NULL", buf != NULL);
     len = netbuf_len((struct netbuf *)buf);
-    }
+  }
 #endif /* (LWIP_UDP || LWIP_RAW) */
 
+#if LWIP_SO_RCVBUF
   SYS_ARCH_DEC(conn->recv_avail, len);
-    /* Register event with callback */
-    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
+#endif /* LWIP_SO_RCVBUF */
+  /* Register event with callback */
+  API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
 
   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
 
@@ -426,7 +434,7 @@ err_t
 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
 {
   LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
-             netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
+             NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
 
   return netconn_recv_data(conn, (void **)new_buf);
 }
@@ -453,7 +461,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
   LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
 
 #if LWIP_TCP
-  if (conn->type == NETCONN_TCP) {
+  if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
     struct pbuf *p = NULL;
     /* This is not a listening netconn, since recvmbox is set */
 
@@ -461,7 +469,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
     if (buf == NULL) {
       NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
       return ERR_MEM;
-      }
+    }
 
     err = netconn_recv_data(conn, (void **)&p);
     if (err != ERR_OK) {
@@ -473,7 +481,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
     buf->p = p;
     buf->ptr = p;
     buf->port = 0;
-    buf->addr = NULL;
+    ipX_addr_set_any(LWIP_IPV6, &buf->addr);
     *new_buf = buf;
     /* don't set conn->last_err: it's only ERR_OK, anyway */
     return ERR_OK;
@@ -499,7 +507,8 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf)
 void
 netconn_recved(struct netconn *conn, u32_t length)
 {
-  if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
+#if LWIP_TCP
+  if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) &&
       (netconn_get_noautorecved(conn))) {
     struct api_msg msg;
     /* Let the stack know that we have taken the data. */
@@ -510,7 +519,11 @@ netconn_recved(struct netconn *conn, u32_t length)
     msg.msg.msg.r.len = length;
     /* don't care for the return value of do_recv */
     TCPIP_APIMSG(&msg);
-    }
+  }
+#else /* LWIP_TCP */
+  LWIP_UNUSED_ARG(conn);
+  LWIP_UNUSED_ARG(length);
+#endif /* LWIP_TCP */
 }
 
 /**
@@ -527,7 +540,7 @@ err_t
 netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
 {
   if (buf != NULL) {
-    buf->addr = addr;
+    ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr);
     buf->port = port;
     return netconn_send(conn, buf);
   }
@@ -569,22 +582,30 @@ netconn_send(struct netconn *conn, struct netbuf *buf)
  * - NETCONN_COPY: data will be copied into memory belonging to the stack
  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
  * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
+ * @param bytes_written pointer to a location that receives the number of written bytes
  * @return ERR_OK if data was sent, any other err_t on error
  */
 err_t
-netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
+netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
+                     u8_t apiflags, size_t *bytes_written)
 {
   struct api_msg msg;
   err_t err;
+  u8_t dontblock;
 
   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
-  LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;);
+  LWIP_ERROR("netconn_write: invalid conn->type",  (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
   if (size == 0) {
     return ERR_OK;
   }
+  dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
+  if (dontblock && !bytes_written) {
+    /* This implies netconn_write() cannot be used for non-blocking send, since
+       it has no way to return the number of bytes written. */
+    return ERR_VAL;
+  }
 
-  /* @todo: for non-blocking write, check if 'size' would ever fit into
-            snd_queue or snd_buf */
+  /* non-blocking write sends as much  */
   msg.function = do_write;
   msg.msg.conn = conn;
   msg.msg.msg.w.dataptr = dataptr;
@@ -594,19 +615,29 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl
      but if it is, this is done inside api_msg.c:do_write(), so we can use the
      non-blocking version here. */
   err = TCPIP_APIMSG(&msg);
+  if ((err == ERR_OK) && (bytes_written != NULL)) {
+    if (dontblock) {
+      /* nonblocking write: maybe the data has been sent partly */
+      *bytes_written = msg.msg.msg.w.len;
+    } else {
+      /* blocking call succeeded: all data has been sent if it */
+      *bytes_written = size;
+    }
+  }
 
   NETCONN_SET_SAFE_ERR(conn, err);
   return err;
 }
 
 /**
- * Close a TCP netconn (doesn't delete it).
+ * Close ot shutdown a TCP netconn (doesn't delete it).
  *
- * @param conn the TCP netconn to close
+ * @param conn the TCP netconn to close or shutdown
+ * @param how fully close or only shutdown one side?
  * @return ERR_OK if the netconn was closed, any other err_t on error
  */
-err_t
-netconn_close(struct netconn *conn)
+static err_t
+netconn_close_shutdown(struct netconn *conn, u8_t how)
 {
   struct api_msg msg;
   err_t err;
@@ -615,6 +646,8 @@ netconn_close(struct netconn *conn)
 
   msg.function = do_close;
   msg.msg.conn = conn;
+  /* shutting down both ends is the same as closing */
+  msg.msg.msg.sd.shut = how;
   /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
      don't use TCPIP_APIMSG here */
   err = tcpip_apimsg(&msg);
@@ -623,7 +656,32 @@ netconn_close(struct netconn *conn)
   return err;
 }
 
-#if LWIP_IGMP
+/**
+ * Close a TCP netconn (doesn't delete it).
+ *
+ * @param conn the TCP netconn to close
+ * @return ERR_OK if the netconn was closed, any other err_t on error
+ */
+err_t
+netconn_close(struct netconn *conn)
+{
+  /* shutting down both ends is the same as closing */
+  return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
+}
+
+/**
+ * Shut down one or both sides of a TCP netconn (doesn't delete it).
+ *
+ * @param conn the TCP netconn to shut down
+ * @return ERR_OK if the netconn was closed, any other err_t on error
+ */
+err_t
+netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
+{
+  return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
+}
+
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
 /**
  * Join multicast groups for UDP netconns.
  *
@@ -647,15 +705,15 @@ netconn_join_leave_group(struct netconn *conn,
 
   msg.function = do_join_leave_group;
   msg.msg.conn = conn;
-  msg.msg.msg.jl.multiaddr = multiaddr;
-  msg.msg.msg.jl.netif_addr = netif_addr;
+  msg.msg.msg.jl.multiaddr = ip_2_ipX(multiaddr);
+  msg.msg.msg.jl.netif_addr = ip_2_ipX(netif_addr);
   msg.msg.msg.jl.join_or_leave = join_or_leave;
   err = TCPIP_APIMSG(&msg);
 
   NETCONN_SET_SAFE_ERR(conn, err);
   return err;
 }
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 
 #if LWIP_DNS
 /**
index 7953f79fd6b1484df35c3dbc1afa7691f5caf59b..9d0895ac104858081126061dc88a8c9992ff2ef7 100644 (file)
@@ -51,6 +51,7 @@
 #include "lwip/tcpip.h"
 #include "lwip/igmp.h"
 #include "lwip/dns.h"
+#include "lwip/mld6.h"
 
 #include <string.h>
 
@@ -88,7 +89,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
   if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
 #if LWIP_SO_RCVBUF
     int recv_avail;
-  SYS_ARCH_GET(conn->recv_avail, recv_avail);
+    SYS_ARCH_GET(conn->recv_avail, recv_avail);
     if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
       return 0;
     }
@@ -112,7 +113,7 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
 
       buf->p = q;
       buf->ptr = q;
-      buf->addr = &(((struct ip_hdr*)(q->payload))->src);
+      ipX_addr_copy(PCB_ISIPV6(pcb), buf->addr, *ipX_current_src_addr());
       buf->port = pcb->protocol;
 
       len = q->tot_len;
@@ -120,7 +121,9 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
         netbuf_delete(buf);
         return 0;
       } else {
+#if LWIP_SO_RCVBUF
         SYS_ARCH_INC(conn->recv_avail, len);
+#endif /* LWIP_SO_RCVBUF */
         /* Register event with callback */
         API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
       }
@@ -173,17 +176,16 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   } else {
     buf->p = p;
     buf->ptr = p;
-    buf->addr = addr;
+    ipX_addr_set_ipaddr(ip_current_is_v6(), &buf->addr, addr);
     buf->port = port;
 #if LWIP_NETBUF_RECVINFO
     {
-      const struct ip_hdr* iphdr = ip_current_header();
       /* get the UDP header - always in the first pbuf, ensured by udp_input */
-      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
+      const struct udp_hdr* udphdr = ipX_next_header_ptr();
 #if LWIP_CHECKSUM_ON_COPY
       buf->flags = NETBUF_FLAG_DESTADDR;
 #endif /* LWIP_CHECKSUM_ON_COPY */
-      buf->toaddr = (ip_addr_t*)&iphdr->dest;
+      ipX_addr_set(ip_current_is_v6(), &buf->toaddr, ipX_current_dest_addr());
       buf->toport_chksum = udphdr->dest;
     }
 #endif /* LWIP_NETBUF_RECVINFO */
@@ -194,7 +196,9 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
     netbuf_delete(buf);
     return;
   } else {
+#if LWIP_SO_RCVBUF
     SYS_ARCH_INC(conn->recv_avail, len);
+#endif /* LWIP_SO_RCVBUF */
     /* Register event with callback */
     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
   }
@@ -248,7 +252,9 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
     /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
     return ERR_MEM;
   } else {
+#if LWIP_SO_RCVBUF
     SYS_ARCH_INC(conn->recv_avail, len);
+#endif /* LWIP_SO_RCVBUF */
     /* Register event with callback */
     API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
   }
@@ -356,14 +362,14 @@ err_tcp(void *arg, err_t err)
 
   /* reset conn->state now before waking up other threads */
   old_state = conn->state;
-    conn->state = NETCONN_NONE;
+  conn->state = NETCONN_NONE;
 
   /* Notify the user layer about a connection error. Used to signal
      select. */
   API_EVENT(conn, NETCONN_EVT_ERROR, 0);
   /* Try to release selects pending on 'read' or 'write', too.
      They will get an error if they actually try to read or write. */
-    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
 
   /* pass NULL-message to recvmbox to wake up pending recv */
@@ -389,7 +395,7 @@ err_tcp(void *arg, err_t err)
       LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
       conn->current_msg->err = err;
       conn->current_msg = NULL;
-    /* wake up the waiting task */
+      /* wake up the waiting task */
       sys_sem_signal(&conn->op_completed);
     }
   } else {
@@ -475,53 +481,57 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
 static void
 pcb_new(struct api_msg_msg *msg)
 {
-   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
+  LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
 
-   /* Allocate a PCB for this connection */
-   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
+  /* Allocate a PCB for this connection */
+  switch(NETCONNTYPE_GROUP(msg->conn->type)) {
 #if LWIP_RAW
-   case NETCONN_RAW:
-     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
-     if(msg->conn->pcb.raw == NULL) {
-      msg->err = ERR_MEM;
-       break;
-     }
-     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
-     break;
+  case NETCONN_RAW:
+    msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
+    if(msg->conn->pcb.raw != NULL) {
+      raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
+    }
+    break;
 #endif /* LWIP_RAW */
 #if LWIP_UDP
-   case NETCONN_UDP:
-     msg->conn->pcb.udp = udp_new();
-     if(msg->conn->pcb.udp == NULL) {
-      msg->err = ERR_MEM;
-       break;
-     }
+  case NETCONN_UDP:
+    msg->conn->pcb.udp = udp_new();
+    if(msg->conn->pcb.udp != NULL) {
 #if LWIP_UDPLITE
-     if (msg->conn->type==NETCONN_UDPLITE) {
-       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
-     }
+      if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) {
+        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
+      }
 #endif /* LWIP_UDPLITE */
-     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
-       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
-     }
-     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
-     break;
+      if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) {
+        udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
+      }
+      udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
+    }
+    break;
 #endif /* LWIP_UDP */
 #if LWIP_TCP
-   case NETCONN_TCP:
-     msg->conn->pcb.tcp = tcp_new();
-     if(msg->conn->pcb.tcp == NULL) {
-      msg->err = ERR_MEM;
-       break;
-     }
-     setup_tcp(msg->conn);
-     break;
+  case NETCONN_TCP:
+    msg->conn->pcb.tcp = tcp_new();
+    if(msg->conn->pcb.tcp != NULL) {
+      setup_tcp(msg->conn);
+    }
+    break;
 #endif /* LWIP_TCP */
-   default:
-     /* Unsupported netconn type, e.g. protocol disabled */
+  default:
+    /* Unsupported netconn type, e.g. protocol disabled */
     msg->err = ERR_VAL;
-     break;
-   }
+    return;
+  }
+  if (msg->conn->pcb.ip == NULL) {
+    msg->err = ERR_MEM;
+  }
+#if LWIP_IPV6
+  else {
+    if (NETCONNTYPE_ISIPV6(msg->conn->type)) {
+      ip_set_v6(msg->conn->pcb.ip, 1);
+    }
+  }
+#endif /* LWIP_IPV6 */
 }
 
 /**
@@ -534,14 +544,14 @@ void
 do_newconn(struct api_msg_msg *msg)
 {
   msg->err = ERR_OK;
-   if(msg->conn->pcb.tcp == NULL) {
-     pcb_new(msg);
-   }
-   /* Else? This "new" connection already has a PCB allocated. */
-   /* Is this an error condition? Should it be deleted? */
-   /* We currently just are happy and return. */
-
-   TCPIP_APIMSG_ACK(msg);
+  if(msg->conn->pcb.tcp == NULL) {
+    pcb_new(msg);
+  }
+  /* Else? This "new" connection already has a PCB allocated. */
+  /* Is this an error condition? Should it be deleted? */
+  /* We currently just are happy and return. */
+
+  TCPIP_APIMSG_ACK(msg);
 }
 
 /**
@@ -614,7 +624,6 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
   conn->socket       = -1;
 #endif /* LWIP_SOCKET */
   conn->callback     = callback;
-  conn->recv_avail   = 0;
 #if LWIP_TCP
   conn->current_msg  = NULL;
   conn->write_offset = 0;
@@ -624,6 +633,7 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
 #endif /* LWIP_SO_RCVTIMEO */
 #if LWIP_SO_RCVBUF
   conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
+  conn->recv_avail   = 0;
 #endif /* LWIP_SO_RCVBUF */
   conn->flags = 0;
   return conn;
@@ -674,13 +684,13 @@ netconn_drain(struct netconn *conn)
   if (sys_mbox_valid(&conn->recvmbox)) {
     while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
 #if LWIP_TCP
-      if (conn->type == NETCONN_TCP) {
+      if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) {
         if(mem != NULL) {
           p = (struct pbuf*)mem;
           /* pcb might be set to NULL already by err_tcp() */
           if (conn->pcb.tcp != NULL) {
             tcp_recved(conn->pcb.tcp, p->tot_len);
-        }
+          }
           pbuf_free(p);
         }
       } else
@@ -708,9 +718,9 @@ netconn_drain(struct netconn *conn)
       if (newconn->pcb.tcp != NULL) {
         tcp_abort(newconn->pcb.tcp);
         newconn->pcb.tcp = NULL;
-    }
+      }
       netconn_free(newconn);
-  }
+    }
     sys_mbox_free(&conn->acceptmbox);
     sys_mbox_set_invalid(&conn->acceptmbox);
   }
@@ -729,27 +739,46 @@ static void
 do_close_internal(struct netconn *conn)
 {
   err_t err;
+  u8_t shut, shut_rx, shut_tx, close;
 
   LWIP_ASSERT("invalid conn", (conn != NULL));
-  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
+  LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP));
   LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
   LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
   LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
 
+  shut = conn->current_msg->msg.sd.shut;
+  shut_rx = shut & NETCONN_SHUT_RD;
+  shut_tx = shut & NETCONN_SHUT_WR;
+  /* shutting down both ends is the same as closing */
+  close = shut == NETCONN_SHUT_RDWR;
+
   /* Set back some callback pointers */
-  tcp_arg(conn->pcb.tcp, NULL);
+  if (close) {
+    tcp_arg(conn->pcb.tcp, NULL);
+  }
   if (conn->pcb.tcp->state == LISTEN) {
     tcp_accept(conn->pcb.tcp, NULL);
   } else {
-    tcp_recv(conn->pcb.tcp, NULL);
-    tcp_accept(conn->pcb.tcp, NULL);
     /* some callbacks have to be reset if tcp_close is not successful */
-    tcp_sent(conn->pcb.tcp, NULL);
-    tcp_poll(conn->pcb.tcp, NULL, 4);
-    tcp_err(conn->pcb.tcp, NULL);
+    if (shut_rx) {
+      tcp_recv(conn->pcb.tcp, NULL);
+      tcp_accept(conn->pcb.tcp, NULL);
+    }
+    if (shut_tx) {
+      tcp_sent(conn->pcb.tcp, NULL);
+    }
+    if (close) {
+      tcp_poll(conn->pcb.tcp, NULL, 4);
+      tcp_err(conn->pcb.tcp, NULL);
+    }
   }
   /* Try to close the connection */
-  err = tcp_close(conn->pcb.tcp);
+  if (shut == NETCONN_SHUT_RDWR) {
+    err = tcp_close(conn->pcb.tcp);
+  } else {
+    err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
+  }
   if (err == ERR_OK) {
     /* Closing succeeded */
     conn->current_msg->err = ERR_OK;
@@ -759,9 +788,15 @@ do_close_internal(struct netconn *conn)
     conn->pcb.tcp = NULL;
     /* Trigger select() in socket layer. Make sure everybody notices activity
        on the connection, error first! */
-    API_EVENT(conn, NETCONN_EVT_ERROR, 0);
-    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
-    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+    if (close) {
+      API_EVENT(conn, NETCONN_EVT_ERROR, 0);
+    }
+    if (shut_rx) {
+      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
+    }
+    if (shut_tx) {
+      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
+    }
     /* wake up the application task */
     sys_sem_signal(&conn->op_completed);
   } else {
@@ -772,6 +807,7 @@ do_close_internal(struct netconn *conn)
     tcp_poll(conn->pcb.tcp, poll_tcp, 4);
     tcp_err(conn->pcb.tcp, err_tcp);
     tcp_arg(conn->pcb.tcp, conn);
+    /* don't restore recv callback: we don't want to receive any more data */
   }
   /* If closing didn't succeed, we get called again either
      from poll_tcp or from sent_tcp */
@@ -792,7 +828,8 @@ do_delconn(struct api_msg_msg *msg)
      (msg->conn->state != NETCONN_LISTEN) &&
      (msg->conn->state != NETCONN_CONNECT)) {
     /* this only happens for TCP netconns */
-    LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
+    LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
+                NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
     msg->err = ERR_INPROGRESS;
   } else {
     LWIP_ASSERT("blocking connect in progress",
@@ -800,42 +837,43 @@ do_delconn(struct api_msg_msg *msg)
     /* Drain and delete mboxes */
     netconn_drain(msg->conn);
 
-  if (msg->conn->pcb.tcp != NULL) {
+    if (msg->conn->pcb.tcp != NULL) {
 
-    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+      switch (NETCONNTYPE_GROUP(msg->conn->type)) {
 #if LWIP_RAW
-    case NETCONN_RAW:
-      raw_remove(msg->conn->pcb.raw);
-      break;
+      case NETCONN_RAW:
+        raw_remove(msg->conn->pcb.raw);
+        break;
 #endif /* LWIP_RAW */
 #if LWIP_UDP
-    case NETCONN_UDP:
-      msg->conn->pcb.udp->recv_arg = NULL;
-      udp_remove(msg->conn->pcb.udp);
-      break;
+      case NETCONN_UDP:
+        msg->conn->pcb.udp->recv_arg = NULL;
+        udp_remove(msg->conn->pcb.udp);
+        break;
 #endif /* LWIP_UDP */
 #if LWIP_TCP
-    case NETCONN_TCP:
+      case NETCONN_TCP:
         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
           msg->conn->write_offset == 0);
-      msg->conn->state = NETCONN_CLOSE;
+        msg->conn->state = NETCONN_CLOSE;
+        msg->msg.sd.shut = NETCONN_SHUT_RDWR;
         msg->conn->current_msg = msg;
-      do_close_internal(msg->conn);
-      /* API_EVENT is called inside do_close_internal, before releasing
-         the application thread, so we can return at this point! */
-      return;
+        do_close_internal(msg->conn);
+        /* API_EVENT is called inside do_close_internal, before releasing
+           the application thread, so we can return at this point! */
+        return;
 #endif /* LWIP_TCP */
-    default:
-      break;
-    }
+      default:
+        break;
+      }
       msg->conn->pcb.tcp = NULL;
-  }
-  /* tcp netconns don't come here! */
+    }
+    /* tcp netconns don't come here! */
 
     /* @todo: this lets select make the socket readable and writable,
        which is wrong! errfd instead? */
-  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
-  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
+    API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
+    API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
   }
   if (sys_sem_valid(&msg->conn->op_completed)) {
     sys_sem_signal(&msg->conn->op_completed);
@@ -909,7 +947,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
   if (conn->current_msg != NULL) {
     conn->current_msg->err = err;
   }
-  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
+  if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) {
     setup_tcp(conn);
   }
   was_blocking = !IN_NONBLOCKING_CONNECT(conn);
@@ -917,12 +955,7 @@ do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
   conn->current_msg = NULL;
   conn->state = NETCONN_NONE;
   if (!was_blocking) {
-    SYS_ARCH_DECL_PROTECT(lev);
-    SYS_ARCH_PROTECT(lev);
-    if (conn->last_err == ERR_INPROGRESS) {
-      conn->last_err = ERR_OK;
-    }
-    SYS_ARCH_UNPROTECT(lev);
+    NETCONN_SET_SAFE_ERR(conn, ERR_OK);
   }
   API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
 
@@ -947,7 +980,7 @@ do_connect(struct api_msg_msg *msg)
     /* This may happen when calling netconn_connect() a second time */
     msg->err = ERR_CLSD;
   } else {
-  switch (NETCONNTYPE_GROUP(msg->conn->type)) {
+    switch (NETCONNTYPE_GROUP(msg->conn->type)) {
 #if LWIP_RAW
   case NETCONN_RAW:
     msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
@@ -964,7 +997,7 @@ do_connect(struct api_msg_msg *msg)
     if (msg->conn->state != NETCONN_NONE) {
       msg->err = ERR_ISCONN;
     } else {
-    setup_tcp(msg->conn);
+      setup_tcp(msg->conn);
       msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
         msg->msg.bc.port, do_connected);
       if (msg->err == ERR_OK) {
@@ -975,8 +1008,8 @@ do_connect(struct api_msg_msg *msg)
           msg->err = ERR_INPROGRESS;
         } else {
           msg->conn->current_msg = msg;
-    /* sys_sem_signal() is called from do_connected (or err_tcp()),
-     * when the connection is established! */
+          /* sys_sem_signal() is called from do_connected (or err_tcp()),
+          * when the connection is established! */
           return;
         }
       }
@@ -986,7 +1019,7 @@ do_connect(struct api_msg_msg *msg)
   default:
     LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
     break;
-  }
+    }
   }
   sys_sem_signal(&msg->conn->op_completed);
 }
@@ -1013,6 +1046,7 @@ do_disconnect(struct api_msg_msg *msg)
   TCPIP_APIMSG_ACK(msg);
 }
 
+#if LWIP_TCP
 /**
  * Set a TCP pcb contained in a netconn into listen mode
  * Called from netconn_listen.
@@ -1022,13 +1056,12 @@ do_disconnect(struct api_msg_msg *msg)
 void
 do_listen(struct api_msg_msg *msg)
 {
-#if LWIP_TCP
   if (ERR_IS_FATAL(msg->conn->last_err)) {
     msg->err = msg->conn->last_err;
   } else {
     msg->err = ERR_CONN;
     if (msg->conn->pcb.tcp != NULL) {
-      if (msg->conn->type == NETCONN_TCP) {
+      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
         if (msg->conn->state == NETCONN_NONE) {
 #if TCP_LISTEN_BACKLOG
           struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
@@ -1048,7 +1081,7 @@ do_listen(struct api_msg_msg *msg)
             msg->err = ERR_OK;
             if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
               msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
-              }
+            }
             if (msg->err == ERR_OK) {
               msg->conn->state = NETCONN_LISTEN;
               msg->conn->pcb.tcp = lpcb;
@@ -1064,9 +1097,9 @@ do_listen(struct api_msg_msg *msg)
       }
     }
   }
-#endif /* LWIP_TCP */
   TCPIP_APIMSG_ACK(msg);
 }
+#endif /* LWIP_TCP */
 
 /**
  * Send some data on a RAW or UDP pcb contained in a netconn
@@ -1085,29 +1118,29 @@ do_send(struct api_msg_msg *msg)
       switch (NETCONNTYPE_GROUP(msg->conn->type)) {
 #if LWIP_RAW
       case NETCONN_RAW:
-        if (msg->msg.b->addr == NULL) {
+        if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
           msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
         } else {
-          msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);
+          msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr));
         }
         break;
 #endif
 #if LWIP_UDP
       case NETCONN_UDP:
 #if LWIP_CHECKSUM_ON_COPY
-        if (msg->msg.b->addr == NULL) {
+        if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
           msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
         } else {
           msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
-            msg->msg.b->addr, msg->msg.b->port,
+            ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port,
             msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
         }
 #else /* LWIP_CHECKSUM_ON_COPY */
-        if (msg->msg.b->addr == NULL) {
+        if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) {
           msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
         } else {
-          msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);
+          msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port);
         }
 #endif /* LWIP_CHECKSUM_ON_COPY */
         break;
@@ -1120,6 +1153,7 @@ do_send(struct api_msg_msg *msg)
   TCPIP_APIMSG_ACK(msg);
 }
 
+#if LWIP_TCP
 /**
  * Indicate data has been received from a TCP pcb contained in a netconn
  * Called from netconn_recv
@@ -1129,16 +1163,15 @@ do_send(struct api_msg_msg *msg)
 void
 do_recv(struct api_msg_msg *msg)
 {
-#if LWIP_TCP
   msg->err = ERR_OK;
-    if (msg->conn->pcb.tcp != NULL) {
-      if (msg->conn->type == NETCONN_TCP) {
+  if (msg->conn->pcb.tcp != NULL) {
+    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
 #if TCP_LISTEN_BACKLOG
-        if (msg->conn->pcb.tcp->state == LISTEN) {
-          tcp_accepted(msg->conn->pcb.tcp);
-        } else
+      if (msg->conn->pcb.tcp->state == LISTEN) {
+        tcp_accepted(msg->conn->pcb.tcp);
+      } else
 #endif /* TCP_LISTEN_BACKLOG */
-        {
+      {
         u32_t remaining = msg->msg.r.len;
         do {
           u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
@@ -1148,11 +1181,9 @@ do_recv(struct api_msg_msg *msg)
       }
     }
   }
-#endif /* LWIP_TCP */
   TCPIP_APIMSG_ACK(msg);
 }
 
-#if LWIP_TCP
 /**
  * See if more data needs to be written from a previous call to netconn_write.
  * Called initially from do_write. If the first call can't send all data
@@ -1167,7 +1198,7 @@ do_recv(struct api_msg_msg *msg)
 static err_t
 do_writemore(struct netconn *conn)
 {
-  err_t err = ERR_OK;
+  err_t err;
   void *dataptr;
   u16_t len, available;
   u8_t write_finished = 0;
@@ -1198,62 +1229,62 @@ do_writemore(struct netconn *conn)
   if (available < len) {
     /* don't try to write more than sendbuf */
     len = available;
+    if (dontblock){ 
+      if (!len) {
+        err = ERR_WOULDBLOCK;
+        goto err_mem;
+      }
+    } else {
 #if LWIP_TCPIP_CORE_LOCKING
-    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+      conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
 #endif
-    apiflags |= TCP_WRITE_FLAG_MORE;
-  }
-  if (dontblock && (len < conn->current_msg->msg.w.len)) {
-    /* failed to send all data at once -> nonblocking write not possible */
-    err = ERR_MEM;
-  }
-  if (err == ERR_OK) {
-    LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
-    err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
+      apiflags |= TCP_WRITE_FLAG_MORE;
+    }
   }
-  if (dontblock && (err == ERR_MEM)) {
-    /* nonblocking write failed */
-    write_finished = 1;
-    err = ERR_WOULDBLOCK;
-    /* let poll_tcp check writable space to mark the pcb
-       writable again */
-    conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
-    /* let select mark this pcb as non-writable. */
-    API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
-  } else {
-    /* if OK or memory error, check available space */
-    if (((err == ERR_OK) || (err == ERR_MEM)) &&
-        ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
-         (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {
+  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
+  err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
+  /* if OK or memory error, check available space */
+  if ((err == ERR_OK) || (err == ERR_MEM)) {
+err_mem:
+    if (dontblock && (len < conn->current_msg->msg.w.len)) {
+      /* non-blocking write did not write everything: mark the pcb non-writable
+         and let poll_tcp check writable space to mark the pcb writable again */
+      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+      conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
+    } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
+               (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
       /* The queued byte- or pbuf-count exceeds the configured low-water limit,
          let select mark this pcb as non-writable. */
       API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+    }
   }
 
   if (err == ERR_OK) {
     conn->write_offset += len;
-      if (conn->write_offset == conn->current_msg->msg.w.len) {
+    if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
+      /* return sent length */
+      conn->current_msg->msg.w.len = conn->write_offset;
       /* everything was written */
       write_finished = 1;
       conn->write_offset = 0;
     }
-      tcp_output(conn->pcb.tcp);
-  } else if (err == ERR_MEM) {
+    tcp_output(conn->pcb.tcp);
+  } else if ((err == ERR_MEM) && !dontblock) {
     /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
        we do NOT return to the application thread, since ERR_MEM is
        only a temporary error! */
 
-      /* tcp_write returned ERR_MEM, try tcp_output anyway */
-      tcp_output(conn->pcb.tcp);
+    /* tcp_write returned ERR_MEM, try tcp_output anyway */
+    tcp_output(conn->pcb.tcp);
 
-  #if LWIP_TCPIP_CORE_LOCKING
-      conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
-  #endif
+#if LWIP_TCPIP_CORE_LOCKING
+    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+#endif
   } else {
     /* On errors != ERR_MEM, we don't try writing any more but return
        the error to the application thread. */
     write_finished = 1;
-  }
+    conn->current_msg->msg.w.len = 0;
   }
 
   if (write_finished) {
@@ -1289,34 +1320,34 @@ do_write(struct api_msg_msg *msg)
   if (ERR_IS_FATAL(msg->conn->last_err)) {
     msg->err = msg->conn->last_err;
   } else {
-    if (msg->conn->type == NETCONN_TCP) {
+    if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
 #if LWIP_TCP
       if (msg->conn->state != NETCONN_NONE) {
         /* netconn is connecting, closing or in blocking write */
         msg->err = ERR_INPROGRESS;
       } else if (msg->conn->pcb.tcp != NULL) {
-      msg->conn->state = NETCONN_WRITE;
-      /* set all the variables used by do_writemore */
+        msg->conn->state = NETCONN_WRITE;
+        /* set all the variables used by do_writemore */
         LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
-        msg->conn->write_offset == 0);
+          msg->conn->write_offset == 0);
         LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
         msg->conn->current_msg = msg;
-      msg->conn->write_offset = 0;
+        msg->conn->write_offset = 0;
 #if LWIP_TCPIP_CORE_LOCKING
         msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
-      if (do_writemore(msg->conn) != ERR_OK) {
-        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
-        UNLOCK_TCPIP_CORE();
+        if (do_writemore(msg->conn) != ERR_OK) {
+          LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
+          UNLOCK_TCPIP_CORE();
           sys_arch_sem_wait(&msg->conn->op_completed, 0);
-        LOCK_TCPIP_CORE();
-        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
-      }
+          LOCK_TCPIP_CORE();
+          LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
+        }
 #else /* LWIP_TCPIP_CORE_LOCKING */
-      do_writemore(msg->conn);
+        do_writemore(msg->conn);
 #endif /* LWIP_TCPIP_CORE_LOCKING */
         /* for both cases: if do_writemore was called, don't ACK the APIMSG
            since do_writemore ACKs it! */
-      return;
+        return;
       } else {
         msg->err = ERR_CONN;
       }
@@ -1342,9 +1373,13 @@ void
 do_getaddr(struct api_msg_msg *msg)
 {
   if (msg->conn->pcb.ip != NULL) {
-    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
-                             msg->conn->pcb.ip->remote_ip);
-    
+    if (msg->msg.ad.local) {
+      ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr),
+        msg->conn->pcb.ip->local_ip);
+    } else {
+      ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), *(msg->msg.ad.ipaddr),
+        msg->conn->pcb.ip->remote_ip);
+    }
     msg->err = ERR_OK;
     switch (NETCONNTYPE_GROUP(msg->conn->type)) {
 #if LWIP_RAW
@@ -1398,18 +1433,26 @@ do_close(struct api_msg_msg *msg)
   /* @todo: abort running write/connect? */
   if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
     /* this only happens for TCP netconns */
-    LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
+    LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP",
+                NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP);
     msg->err = ERR_INPROGRESS;
-  } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
-    /* Drain and delete mboxes */
-    netconn_drain(msg->conn);
-    LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
-      msg->conn->write_offset == 0);
+  } else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) {
+    if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
+      /* LISTEN doesn't support half shutdown */
+      msg->err = ERR_CONN;
+    } else {
+      if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
+        /* Drain and delete mboxes */
+        netconn_drain(msg->conn);
+      }
+      LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
+        msg->conn->write_offset == 0);
       msg->conn->state = NETCONN_CLOSE;
-    msg->conn->current_msg = msg;
+      msg->conn->current_msg = msg;
       do_close_internal(msg->conn);
       /* for tcp netconns, do_close_internal ACKs the message */
-    return;
+      return;
+    }
   } else
 #endif /* LWIP_TCP */
   {
@@ -1418,7 +1461,7 @@ do_close(struct api_msg_msg *msg)
   sys_sem_signal(&msg->conn->op_completed);
 }
 
-#if LWIP_IGMP
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
 /**
  * Join multicast groups for UDP netconns.
  * Called from netconn_join_leave_group
@@ -1434,10 +1477,28 @@ do_join_leave_group(struct api_msg_msg *msg)
     if (msg->conn->pcb.tcp != NULL) {
       if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
 #if LWIP_UDP
-        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
-          msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
-        } else {
-          msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+        if (PCB_ISIPV6(msg->conn->pcb.udp)) {
+          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
+            msg->err = mld6_joingroup(ipX_2_ip6(msg->msg.jl.netif_addr),
+              ipX_2_ip6(msg->msg.jl.multiaddr));
+          } else {
+            msg->err = mld6_leavegroup(ipX_2_ip6(msg->msg.jl.netif_addr),
+              ipX_2_ip6(msg->msg.jl.multiaddr));
+          }
+        }
+        else
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+        {
+#if LWIP_IGMP
+          if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
+            msg->err = igmp_joingroup(ipX_2_ip(msg->msg.jl.netif_addr),
+              ipX_2_ip(msg->msg.jl.multiaddr));
+          } else {
+            msg->err = igmp_leavegroup(ipX_2_ip(msg->msg.jl.netif_addr),
+              ipX_2_ip(msg->msg.jl.multiaddr));
+          }
+#endif /* LWIP_IGMP */
         }
 #endif /* LWIP_UDP */
 #if (LWIP_TCP || LWIP_RAW)
@@ -1451,7 +1512,7 @@ do_join_leave_group(struct api_msg_msg *msg)
   }
   TCPIP_APIMSG_ACK(msg);
 }
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 
 #if LWIP_DNS
 /**
index f965c9810db360be970724b731399e23b39c18bf..92fa8b7dba13a02d419dfa303973550812e75f2c 100644 (file)
@@ -44,19 +44,19 @@ static const char *err_strerr[] = {
            "Ok.",                    /* ERR_OK          0  */
            "Out of memory error.",   /* ERR_MEM        -1  */
            "Buffer error.",          /* ERR_BUF        -2  */
-           "Timeout.",               /* ERR_TIMEOUT    -3 */
+           "Timeout.",               /* ERR_TIMEOUT    -3  */
            "Routing problem.",       /* ERR_RTE        -4  */
            "Operation in progress.", /* ERR_INPROGRESS -5  */
            "Illegal value.",         /* ERR_VAL        -6  */
            "Operation would block.", /* ERR_WOULDBLOCK -7  */
-           "Connection aborted.",    /* ERR_ABRT       -8  */
-           "Connection reset.",      /* ERR_RST        -9  */
-           "Connection closed.",     /* ERR_CLSD       -10 */
-           "Not connected.",         /* ERR_CONN       -11 */
-           "Illegal argument.",      /* ERR_ARG        -12 */
-           "Address in use.",        /* ERR_USE        -13 */
-           "Low-level netif error.", /* ERR_IF         -14 */
-           "Already connected.",     /* ERR_ISCONN     -15 */
+           "Address in use.",        /* ERR_USE        -8  */
+           "Already connected.",     /* ERR_ISCONN     -9  */
+           "Connection aborted.",    /* ERR_ABRT       -10 */
+           "Connection reset.",      /* ERR_RST        -11 */
+           "Connection closed.",     /* ERR_CLSD       -12 */
+           "Not connected.",         /* ERR_CONN       -13 */
+           "Illegal argument.",      /* ERR_ARG        -14 */
+           "Low-level netif error.", /* ERR_IF         -15 */
 };
 
 /**
index d2d2e42e185d39ddd62720fd30ebc15c2d004817..0ccd2bce3271826e27883869c273d37f57911f13 100644 (file)
@@ -61,7 +61,7 @@ netbuf *netbuf_new(void)
   if (buf != NULL) {
     buf->p = NULL;
     buf->ptr = NULL;
-    buf->addr = NULL;
+    ipX_addr_set_any(LWIP_IPV6, &buf->addr);
     buf->port = 0;
 #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
 #if LWIP_CHECKSUM_ON_COPY
@@ -69,7 +69,7 @@ netbuf *netbuf_new(void)
 #endif /* LWIP_CHECKSUM_ON_COPY */
     buf->toport_chksum = 0;
 #if LWIP_NETBUF_RECVINFO
-    buf->toaddr = NULL;
+    ipX_addr_set_any(LWIP_IPV6, &buf->toaddr);
 #endif /* LWIP_NETBUF_RECVINFO */
 #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
     return buf;
index 29ccbc58c3f02851b218b9c5fbecddcc6d48ac75..a7e4e06bca2bcd4efe371724367139b3cac26a59 100644 (file)
@@ -91,7 +91,7 @@ lwip_gethostbyname(const char *name)
   HOSTENT_STORAGE struct hostent s_hostent;
   HOSTENT_STORAGE char *s_aliases;
   HOSTENT_STORAGE ip_addr_t s_hostent_addr;
-  HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2] = { 0 };
+  HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
 
   /* query host IP address */
   err = netconn_gethostbyname(name, &addr);
@@ -104,6 +104,7 @@ lwip_gethostbyname(const char *name)
   /* fill hostent */
   s_hostent_addr = addr;
   s_phostent_addr[0] = &s_hostent_addr;
+  s_phostent_addr[1] = NULL;
   s_hostent.h_name = (char*)name;
   s_hostent.h_aliases = &s_aliases;
   s_hostent.h_addrtype = AF_INET;
@@ -118,7 +119,7 @@ lwip_gethostbyname(const char *name)
     u8_t idx;
     for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx]));
-      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx]));
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n", idx, s_hostent.h_aliases[idx]));
     }
   }
   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype));
index 252f4aa66ee59e69c7453fc774c82b9e7987d507..e3e01ca4f3dc66e5c55609c8eae3a9c583a1c902 100644 (file)
 
 #include <string.h>
 
+#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \
+      (sin)->sin_len = sizeof(struct sockaddr_in); \
+      (sin)->sin_family = AF_INET; \
+      (sin)->sin_port = htons((port)); \
+      inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \
+      memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
+#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \
+    inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \
+    (port) = ntohs((sin)->sin_port); }while(0)
+
+#if LWIP_IPV6
+#define IS_SOCK_ADDR_LEN_VALID(namelen)  (((namelen) == sizeof(struct sockaddr_in)) || \
+                                         ((namelen) == sizeof(struct sockaddr_in6)))
+#define IS_SOCK_ADDR_TYPE_VALID(name)    (((name)->sa_family == AF_INET) || \
+                                         ((name)->sa_family == AF_INET6))
+#define SOCK_ADDR_TYPE_MATCH(name, sock) \
+       ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
+       (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
+#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \
+      (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
+      (sin6)->sin6_family = AF_INET6; \
+      (sin6)->sin6_port = htons((port)); \
+      (sin6)->sin6_flowinfo = 0; \
+      inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0)
+#define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \
+    if (isipv6) { \
+      IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
+    } else { \
+      IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
+    } } while(0)
+#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \
+    inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \
+    (port) = ntohs((sin6)->sin6_port); }while(0)
+#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \
+    if (isipv6) { \
+      SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \
+    } else { \
+      SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \
+    } } while(0)
+#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
+  (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
+#else /* LWIP_IPV6 */
+#define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in))
+#define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET)
+#define SOCK_ADDR_TYPE_MATCH(name, sock) 1
+#define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \
+        IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
+#define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \
+      SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port)
+#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
+#endif /* LWIP_IPV6 */
+
+#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name)    (((name)->sa_family == AF_UNSPEC) || \
+                                                    IS_SOCK_ADDR_TYPE_VALID(name))
+#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
+                                                    SOCK_ADDR_TYPE_MATCH(name, sock))
+#define IS_SOCK_ADDR_ALIGNED(name)      ((((mem_ptr_t)(name)) % 4) == 0)
+
+
+
 #define NUM_SOCKETS MEMP_NUM_NETCONN
 
 /** Contains all internal pointers and states used for a socket */
@@ -105,8 +165,10 @@ struct lwip_select_cb {
 struct lwip_setgetsockopt_data {
   /** socket struct for which to change options */
   struct lwip_sock *sock;
+#ifdef LWIP_DEBUG
   /** socket index for which to change options */
   int s;
+#endif /* LWIP_DEBUG */
   /** level of the option to process */
   int level;
   /** name of the option to process */
@@ -120,6 +182,18 @@ struct lwip_setgetsockopt_data {
   err_t err;
 };
 
+/** A struct sockaddr replacement that has the same alignment as sockaddr_in/
+ *  sockaddr_in6 if instantiated.
+ */
+union sockaddr_aligned {
+   struct sockaddr sa;
+#if LWIP_IPV6
+   struct sockaddr_in6 sin6;
+#endif /* LWIP_IPV6 */
+   struct sockaddr_in sin;
+};
+
+
 /** The global array of available sockets */
 static struct lwip_sock sockets[NUM_SOCKETS];
 /** The global list of tasks waiting for select */
@@ -139,14 +213,14 @@ static const int err_to_errno_table[] = {
   EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
   EINVAL,        /* ERR_VAL        -6      Illegal value.           */
   EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
-  ECONNABORTED,  /* ERR_ABRT       -8      Connection aborted.      */
-  ECONNRESET,    /* ERR_RST        -9      Connection reset.        */
-  ESHUTDOWN,     /* ERR_CLSD       -10     Connection closed.       */
-  ENOTCONN,      /* ERR_CONN       -11     Not connected.           */
-  EIO,           /* ERR_ARG        -12     Illegal argument.        */
-  EADDRINUSE,    /* ERR_USE        -13     Address in use.          */
-  -1,            /* ERR_IF         -14     Low-level netif error    */
-  -1,            /* ERR_ISCONN     -15     Already connected.       */
+  EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
+  EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
+  ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
+  ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
+  ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
+  ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
+  EIO,           /* ERR_ARG        -14     Illegal argument.        */
+  -1,            /* ERR_IF         -15     Low-level netif error    */
 };
 
 #define ERR_TO_ERRNO_TABLE_SIZE \
@@ -160,9 +234,9 @@ static const int err_to_errno_table[] = {
 #ifndef set_errno
 #define set_errno(err) errno = (err)
 #endif
-#else
+#else /* ERRNO */
 #define set_errno(err)
-#endif
+#endif /* ERRNO */
 
 #define sock_set_errno(sk, e) do { \
   sk->err = (e); \
@@ -257,7 +331,7 @@ alloc_socket(struct netconn *newconn, int accepted)
       sockets[i].rcvevent   = 0;
       /* TCP sendbuf is empty, but the socket is not yet writable until connected
        * (unless it has been created by accept()). */
-      sockets[i].sendevent  = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
+      sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
       sockets[i].errevent   = 0;
       sockets[i].err        = 0;
       sockets[i].select_waiting = 0;
@@ -311,10 +385,9 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
 {
   struct lwip_sock *sock, *nsock;
   struct netconn *newconn;
-  ip_addr_t naddr;
+  ipX_addr_t naddr;
   u16_t port;
   int newsock;
-  struct sockaddr_in sin;
   err_t err;
   SYS_ARCH_DECL_PROTECT(lev);
 
@@ -341,30 +414,26 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
   /* Prevent automatic window updates, we do this on our own! */
   netconn_set_noautorecved(newconn, 1);
 
-  /* get the IP address and port of the remote host */
-  err = netconn_peer(newconn, &naddr, &port);
-  if (err != ERR_OK) {
-    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
-    netconn_delete(newconn);
-    sock_set_errno(sock, err_to_errno(err));
-    return -1;
-  }
-
   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
    * not be NULL if addr is valid.
    */
-  if (NULL != addr) {
+  if (addr != NULL) {
+    union sockaddr_aligned tempaddr;
+    /* get the IP address and port of the remote host */
+    err = netconn_peer(newconn, ipX_2_ip(&naddr), &port);
+    if (err != ERR_OK) {
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
+      netconn_delete(newconn);
+      sock_set_errno(sock, err_to_errno(err));
+      return -1;
+    }
     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
-    memset(&sin, 0, sizeof(sin));
-    sin.sin_len = sizeof(sin);
-    sin.sin_family = AF_INET;
-    sin.sin_port = htons(port);
-    inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
-
-    if (*addrlen > sizeof(sin))
-      *addrlen = sizeof(sin);
 
-    MEMCPY(addr, &sin, *addrlen);
+    IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port);
+    if (*addrlen > tempaddr.sa.sa_len) {
+      *addrlen = tempaddr.sa.sa_len;
+    }
+    MEMCPY(addr, &tempaddr, *addrlen);
   }
 
   newsock = alloc_socket(newconn, 1);
@@ -387,9 +456,12 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
   newconn->socket = newsock;
   SYS_ARCH_UNPROTECT(lev);
 
-  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
-  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
-  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
+  if (addr != NULL) {
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" addr="));
+    ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), SOCKETS_DEBUG, &naddr);
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
+  }
 
   sock_set_errno(sock, 0);
   return newsock;
@@ -399,30 +471,33 @@ int
 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
 {
   struct lwip_sock *sock;
-  ip_addr_t local_addr;
+  ipX_addr_t local_addr;
   u16_t local_port;
   err_t err;
-  const struct sockaddr_in *name_in;
 
   sock = get_socket(s);
   if (!sock) {
     return -1;
   }
 
+  if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
+    /* sockaddr does not match socket type (IPv4/IPv6) */
+    sock_set_errno(sock, err_to_errno(ERR_VAL));
+    return -1;
+  }
+
   /* check size, familiy and alignment of 'name' */
-  LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
-             ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
+  LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
+             IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
-  name_in = (const struct sockaddr_in *)(void*)name;
-
-  inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
-  local_port = name_in->sin_port;
+  LWIP_UNUSED_ARG(namelen);
 
+  SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port);
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
-  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
-  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
+  ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
 
-  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
+  err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), local_port);
 
   if (err != ERR_OK) {
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
@@ -449,7 +524,7 @@ lwip_close(int s)
   }
 
   if(sock->conn != NULL) {
-    is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
+    is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
   } else {
     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
   }
@@ -466,34 +541,35 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
 {
   struct lwip_sock *sock;
   err_t err;
-  const struct sockaddr_in *name_in;
 
   sock = get_socket(s);
   if (!sock) {
     return -1;
   }
 
+  if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
+    /* sockaddr does not match socket type (IPv4/IPv6) */
+   sock_set_errno(sock, err_to_errno(ERR_VAL));
+   return -1;
+  }
+
   /* check size, familiy and alignment of 'name' */
-  LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
-             ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
+  LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
+             IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
-  name_in = (const struct sockaddr_in *)(void*)name;
-
-  if (name_in->sin_family == AF_UNSPEC) {
+  LWIP_UNUSED_ARG(namelen);
+  if (name->sa_family == AF_UNSPEC) {
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
     err = netconn_disconnect(sock->conn);
   } else {
-    ip_addr_t remote_addr;
+    ipX_addr_t remote_addr;
     u16_t remote_port;
-
-    inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
-    remote_port = name_in->sin_port;
-
+    SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port);
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
-    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
-    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
+    ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr);
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
 
-    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
+    err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), remote_port);
   }
 
   if (err != ERR_OK) {
@@ -545,16 +621,14 @@ lwip_listen(int s, int backlog)
 
 int
 lwip_recvfrom(int s, void *mem, size_t len, int flags,
-        struct sockaddr *from, socklen_t *fromlen)
+              struct sockaddr *from, socklen_t *fromlen)
 {
   struct lwip_sock *sock;
   void             *buf = NULL;
   struct pbuf      *p;
   u16_t            buflen, copylen;
   int              off = 0;
-  ip_addr_t        *addr;
-  u16_t               port;
-  u8_t                done = 0;
+  u8_t             done = 0;
   err_t            err;
 
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
@@ -585,8 +659,8 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       }
 
       /* No data was left from the previous operation, so we try to get
-      some from the network. */
-      if (netconn_type(sock->conn) == NETCONN_TCP) {
+         some from the network. */
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
         err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
       } else {
         err = netconn_recv(sock->conn, (struct netbuf **)&buf);
@@ -607,7 +681,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
           s, lwip_strerr(err)));
         sock_set_errno(sock, err_to_errno(err));
         if (err == ERR_CLSD) {
-        return 0;
+          return 0;
         } else {
           return -1;
         }
@@ -616,7 +690,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       sock->lastdata = buf;
     }
 
-    if (netconn_type(sock->conn) == NETCONN_TCP) {
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
       p = (struct pbuf *)buf;
     } else {
       p = ((struct netbuf *)buf)->p;
@@ -639,7 +713,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
 
     off += copylen;
 
-    if (netconn_type(sock->conn) == NETCONN_TCP) {
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
       len -= copylen;
       if ( (len <= 0) || 
@@ -654,47 +728,32 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
 
     /* Check to see from where the data was.*/
     if (done) {
-      ip_addr_t fromaddr;
-      if (from && fromlen) {
-        struct sockaddr_in sin;
-
-        if (netconn_type(sock->conn) == NETCONN_TCP) {
-          addr = &fromaddr;
-          netconn_getaddr(sock->conn, addr, &port, 0);
-        } else {
-          addr = netbuf_fromaddr((struct netbuf *)buf);
-          port = netbuf_fromport((struct netbuf *)buf);
-        }
-
-        memset(&sin, 0, sizeof(sin));
-        sin.sin_len = sizeof(sin);
-        sin.sin_family = AF_INET;
-        sin.sin_port = htons(port);
-        inet_addr_from_ipaddr(&sin.sin_addr, addr);
-
-        if (*fromlen > sizeof(sin)) {
-          *fromlen = sizeof(sin);
-        }
-
-        MEMCPY(from, &sin, *fromlen);
-
+#if !SOCKETS_DEBUG
+      if (from && fromlen)
+#endif /* !SOCKETS_DEBUG */
+      {
+        u16_t port;
+        ipX_addr_t tmpaddr;
+        ipX_addr_t *fromaddr;
+        union sockaddr_aligned saddr;
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
-        ip_addr_debug_print(SOCKETS_DEBUG, addr);
-        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
-      } else {
-#if SOCKETS_DEBUG
-        if (netconn_type(sock->conn) == NETCONN_TCP) {
-          addr = &fromaddr;
-          netconn_getaddr(sock->conn, addr, &port, 0);
+        if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
+          fromaddr = &tmpaddr;
+          /* @todo: this does not work for IPv6, yet */
+          netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0);
         } else {
-          addr = netbuf_fromaddr((struct netbuf *)buf);
           port = netbuf_fromport((struct netbuf *)buf);
+          fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf);
         }
-
-        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
-        ip_addr_debug_print(SOCKETS_DEBUG, addr);
+        IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
+          &saddr, fromaddr, port);
+        ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
+          SOCKETS_DEBUG, fromaddr);
         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
-#endif /*  SOCKETS_DEBUG */
+        if (*fromlen > saddr.sa.sa_len) {
+          *fromlen = saddr.sa.sa_len;
+        }
+        MEMCPY(from, &saddr, *fromlen);
       }
     }
 
@@ -703,7 +762,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
       /* If this is a TCP socket, check if there is data left in the
          buffer. If so, it should be saved in the sock structure for next
          time around. */
-      if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
+      if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
         sock->lastdata = buf;
         sock->lastoffset += copylen;
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
@@ -711,7 +770,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
         sock->lastdata = NULL;
         sock->lastoffset = 0;
         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
-        if (netconn_type(sock->conn) == NETCONN_TCP) {
+        if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
           pbuf_free((struct pbuf *)buf);
         } else {
           netbuf_delete((struct netbuf *)buf);
@@ -720,7 +779,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags,
     }
   } while (!done);
 
-  if (off > 0) {
+  if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) {
     /* update receive window */
     netconn_recved(sock->conn, (u32_t)off);
   }
@@ -746,6 +805,7 @@ lwip_send(int s, const void *data, size_t size, int flags)
   struct lwip_sock *sock;
   err_t err;
   u8_t write_flags;
+  size_t written;
 
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
                               s, data, size, flags));
@@ -755,31 +815,24 @@ lwip_send(int s, const void *data, size_t size, int flags)
     return -1;
   }
 
-  if (sock->conn->type != NETCONN_TCP) {
+  if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
 #if (LWIP_UDP || LWIP_RAW)
     return lwip_sendto(s, data, size, flags, NULL, 0);
-#else
+#else /* (LWIP_UDP || LWIP_RAW) */
     sock_set_errno(sock, err_to_errno(ERR_ARG));
     return -1;
 #endif /* (LWIP_UDP || LWIP_RAW) */
   }
 
-  if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
-    if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
-      /* too much data to ever send nonblocking! */
-      sock_set_errno(sock, EMSGSIZE);
-      return -1;
-    }
-  }
-
   write_flags = NETCONN_COPY |
     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
-  err = netconn_write(sock->conn, data, size, write_flags);
+  written = 0;
+  err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
 
-  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
   sock_set_errno(sock, err_to_errno(err));
-  return (err == ERR_OK ? (int)size : -1);
+  return (err == ERR_OK ? (int)written : -1);
 }
 
 int
@@ -787,13 +840,11 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
        const struct sockaddr *to, socklen_t tolen)
 {
   struct lwip_sock *sock;
-  ip_addr_t remote_addr;
   err_t err;
   u16_t short_size;
-  const struct sockaddr_in *to_in;
+  u16_t remote_port;
 #if !LWIP_TCPIP_CORE_LOCKING
   struct netbuf buf;
-  u16_t remote_port;
 #endif
 
   sock = get_socket(s);
@@ -801,34 +852,45 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
     return -1;
   }
 
-  if (sock->conn->type == NETCONN_TCP) {
+  if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
 #if LWIP_TCP
     return lwip_send(s, data, size, flags);
-#else
+#else /* LWIP_TCP */
+    LWIP_UNUSED_ARG(flags);
     sock_set_errno(sock, err_to_errno(ERR_ARG));
     return -1;
 #endif /* LWIP_TCP */
   }
 
+  if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
+    /* sockaddr does not match socket type (IPv4/IPv6) */
+    sock_set_errno(sock, err_to_errno(ERR_VAL));
+    return -1;
+  }
+
   /* @todo: split into multiple sendto's? */
   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
   short_size = (u16_t)size;
   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
-             ((tolen == sizeof(struct sockaddr_in)) &&
-             ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
+             (IS_SOCK_ADDR_LEN_VALID(tolen) &&
+             IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
-  to_in = (const struct sockaddr_in *)(void*)to;
+  LWIP_UNUSED_ARG(tolen);
 
 #if LWIP_TCPIP_CORE_LOCKING
-  /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
-  { struct pbuf* p;
-  
+  /* Special speedup for fast UDP/RAW sending: call the raw API directly
+     instead of using the netconn functions. */
+  {
+    struct pbuf* p;
+    ipX_addr_t *remote_addr;
+    ipX_addr_t remote_addr_tmp;
+
 #if LWIP_NETIF_TX_SINGLE_PBUF
     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
     if (p != NULL) {
 #if LWIP_CHECKSUM_ON_COPY
       u16_t chksum = 0;
-      if (sock->conn->type != NETCONN_RAW) {
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
         chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
       } else
 #endif /* LWIP_CHECKSUM_ON_COPY */
@@ -838,20 +900,35 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
     if (p != NULL) {
       p->payload = (void*)data;
 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-      
-      inet_addr_to_ipaddr(&remote_addr, &to_in->sin_addr);
-      
+
+      if (to != NULL) {
+        SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6,
+          to, &remote_addr_tmp, remote_port);
+        remote_addr = &remote_addr_tmp;
+      } else {
+        remote_addr = &sock->conn->pcb.raw->remote_ip;
+        if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
+          remote_port = 0;
+        } else {
+          remote_port = sock->conn->pcb.udp->remote_port;
+        }
+      }
+
       LOCK_TCPIP_CORE();
-      if (sock->conn->type == NETCONN_RAW) {
-        err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) {
+        err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr));
       } else {
+#if LWIP_UDP
 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
         err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
-          &remote_addr, ntohs(to_in->sin_port), 1, chksum);
+          ipX_2_ip(remote_addr), remote_port, 1, chksum);
 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
         err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
-          &remote_addr, ntohs(to_in->sin_port));
+          ipX_2_ip(remote_addr), remote_port);
 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
+#else /* LWIP_UDP */
+        err = ERR_ARG;
+#endif /* LWIP_UDP */
       }
       UNLOCK_TCPIP_CORE();
       
@@ -860,27 +937,25 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
       err = ERR_MEM;
     }
   }
-#else
+#else /* LWIP_TCPIP_CORE_LOCKING */
   /* initialize a buffer */
   buf.p = buf.ptr = NULL;
 #if LWIP_CHECKSUM_ON_COPY
   buf.flags = 0;
 #endif /* LWIP_CHECKSUM_ON_COPY */
   if (to) {
-    inet_addr_to_ipaddr(&remote_addr, &to_in->sin_addr);
-    remote_port           = ntohs(to_in->sin_port);
-    netbuf_fromaddr(&buf) = &remote_addr;
-    netbuf_fromport(&buf) = remote_port;
+    SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port);
   } else {
-    ip_addr_set_zero(&remote_addr);
-    remote_port      = 0;
-    netbuf_fromaddr(&buf) = NULL;
-    netbuf_fromport(&buf) = 0;
+    remote_port = 0;
+    ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
   }
+  netbuf_fromport(&buf) = remote_port;
+
 
-  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
               s, data, short_size, flags));
-  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
+  ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
+    SOCKETS_DEBUG, &buf.addr);
   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
 
   /* make the buffer point to the data that should be sent */
@@ -890,15 +965,15 @@ lwip_sendto(int s, const void *data, size_t size, int flags,
     err = ERR_MEM;
   } else {
 #if LWIP_CHECKSUM_ON_COPY
-    if (sock->conn->type != NETCONN_RAW) {
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
       netbuf_set_chksum(&buf, chksum);
       err = ERR_OK;
     } else
 #endif /* LWIP_CHECKSUM_ON_COPY */
     {
-    err = netbuf_take(&buf, data, short_size);
-  }
+      err = netbuf_take(&buf, data, short_size);
+    }
   }
 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
   err = netbuf_ref(&buf, data, short_size);
@@ -921,23 +996,27 @@ lwip_socket(int domain, int type, int protocol)
   struct netconn *conn;
   int i;
 
-  LWIP_UNUSED_ARG(domain);
+#if !LWIP_IPV6
+  LWIP_UNUSED_ARG(domain); /* @todo: check this */
+#endif /* LWIP_IPV6 */
 
   /* create a netconn */
   switch (type) {
   case SOCK_RAW:
-    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
+    conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
+                                               (u8_t)protocol, event_callback);
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
     break;
   case SOCK_DGRAM:
-    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
-                 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
+    conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
+                 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
+                 event_callback);
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
     break;
   case SOCK_STREAM:
-    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
+    conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
     if (conn != NULL) {
@@ -1001,13 +1080,13 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep
   fd_set lreadset, lwriteset, lexceptset;
   struct lwip_sock *sock;
   SYS_ARCH_DECL_PROTECT(lev);
-  
+
   FD_ZERO(&lreadset);
   FD_ZERO(&lwriteset);
   FD_ZERO(&lexceptset);
-  
+
   /* Go through each socket in each list to count number of sockets which
-  currently match */
+     currently match */
   for(i = 0; i < maxfdp1; i++) {
     void* lastdata = NULL;
     s16_t rcvevent = 0;
@@ -1024,18 +1103,18 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep
     }
     SYS_ARCH_UNPROTECT(lev);
     /* ... then examine it: */
-      /* See if netconn of this socket is ready for read */
+    /* See if netconn of this socket is ready for read */
     if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
-        FD_SET(i, &lreadset);
-        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
-        nready++;
-      }
-      /* See if netconn of this socket is ready for write */
+      FD_SET(i, &lreadset);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
+      nready++;
+    }
+    /* See if netconn of this socket is ready for write */
     if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
-        FD_SET(i, &lwriteset);
-        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
-        nready++;
-      }
+      FD_SET(i, &lwriteset);
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
+      nready++;
+    }
     /* See if netconn of this socket had an error */
     if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
       FD_SET(i, &lexceptset);
@@ -1047,7 +1126,7 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep
   *readset_out = lreadset;
   *writeset_out = lwriteset;
   *exceptset_out = lexceptset;
-  
+
   LWIP_ASSERT("nready >= 0", nready >= 0);
   return nready;
 }
@@ -1057,7 +1136,7 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep
  */
 int
 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
-               struct timeval *timeout)
+            struct timeval *timeout)
 {
   u32_t waitres = 0;
   int nready;
@@ -1085,7 +1164,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
          or we would have returned earlier. */
       goto return_copy_fdsets;
     }
-  
+
     /* None ready: add our semaphore to list:
        We don't actually need any dynamic memory. Our entry on the
        list is only valid while we are in this function, so it's ok
@@ -1103,10 +1182,10 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
       set_errno(ENOMEM);
       return -1;
     }
-    
+
     /* Protect the select_cb_list */
     SYS_ARCH_PROTECT(lev);
-    
+
     /* Put this select_cb on top of list */
     select_cb.next = select_cb_list;
     if (select_cb_list != NULL) {
@@ -1115,10 +1194,10 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
     select_cb_list = &select_cb;
     /* Increasing this counter tells even_callback that the list has changed. */
     select_cb_ctr++;
-    
+
     /* Now we can safely unprotect */
     SYS_ARCH_UNPROTECT(lev);
-    
+
     /* Increase select_waiting for each socket we are interested in */
     for(i = 0; i < maxfdp1; i++) {
       if ((readset && FD_ISSET(i, readset)) ||
@@ -1139,16 +1218,16 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
     if (!nready) {
       /* Still none ready, just wait to be woken */
       if (timeout == 0) {
-      /* Wait forever */
-      msectimeout = 0;
+        /* Wait forever */
+        msectimeout = 0;
       } else {
-      msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
+        msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
         if (msectimeout == 0) {
           /* Wait 1ms at least (0 means wait forever) */
-        msectimeout = 1;
-    }
+          msectimeout = 1;
+        }
       }
-    
+
       waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
     }
     /* Increase select_waiting for each socket we are interested in */
@@ -1168,16 +1247,18 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
     SYS_ARCH_PROTECT(lev);
     if (select_cb.next != NULL) {
       select_cb.next->prev = select_cb.prev;
-        }
+    }
     if (select_cb_list == &select_cb) {
       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
       select_cb_list = select_cb.next;
     } else {
       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
       select_cb.prev->next = select_cb.next;
-      }
+    }
+    /* Increasing this counter tells even_callback that the list has changed. */
+    select_cb_ctr++;
     SYS_ARCH_UNPROTECT(lev);
-    
+
     sys_sem_free(&select_cb.sem);
     if (waitres == SYS_ARCH_TIMEOUT)  {
       /* Timeout */
@@ -1186,11 +1267,11 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
          or we would have returned earlier. */
       goto return_copy_fdsets;
     }
-    
+
     /* See what's set */
     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
   }
-  
+
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
 return_copy_fdsets:
   set_errno(0);
@@ -1203,8 +1284,6 @@ return_copy_fdsets:
   if (exceptset) {
     *exceptset = lexceptset;
   }
-  
-  
   return nready;
 }
 
@@ -1218,6 +1297,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
   int s;
   struct lwip_sock *sock;
   struct lwip_select_cb *scb;
+  int last_select_cb_ctr;
   SYS_ARCH_DECL_PROTECT(lev);
 
   LWIP_UNUSED_ARG(len);
@@ -1280,56 +1360,51 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
     return;
   }
 
-  SYS_ARCH_UNPROTECT(lev);
-
   /* Now decide if anyone is waiting for this socket */
-  /* NOTE: This code is written this way to protect the select link list
-     but to avoid a deadlock situation by releasing select_lock before
-     signalling for the select. This means we need to go through the list
-     multiple times ONLY IF a select was actually waiting. We go through
-     the list the number of waiting select calls + 1. This list is
-     expected to be small. */
-  while (1) {
-    int last_select_cb_ctr;
-    SYS_ARCH_PROTECT(lev);
-    for (scb = select_cb_list; scb; scb = scb->next) {
-      /* @todo: unprotect with each loop and check for changes? */
-      if (scb->sem_signalled == 0) {
-        /* Test this select call for our socket */
+  /* NOTE: This code goes through the select_cb_list list multiple times
+     ONLY IF a select was actually waiting. We go through the list the number
+     of waiting select calls + 1. This list is expected to be small. */
+
+  /* At this point, SYS_ARCH is still protected! */
+again:
+  for (scb = select_cb_list; scb != NULL; scb = scb->next) {
+    if (scb->sem_signalled == 0) {
+      /* semaphore not signalled yet */
+      int do_signal = 0;
+      /* Test this select call for our socket */
+      if (sock->rcvevent > 0) {
         if (scb->readset && FD_ISSET(s, scb->readset)) {
-          if (sock->rcvevent > 0) {
-            break;
-          }
+          do_signal = 1;
         }
-        if (scb->writeset && FD_ISSET(s, scb->writeset)) {
-          if (sock->sendevent != 0) {
-            break;
       }
-    }
-        if (scb->exceptset && FD_ISSET(s, scb->exceptset)) {
-          if (sock->errevent != 0) {
-            break;
-          }
+      if (sock->sendevent != 0) {
+        if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
+          do_signal = 1;
         }
       }
-      /* unlock interrupts with each step */
-      last_select_cb_ctr = select_cb_ctr;
-      SYS_ARCH_UNPROTECT(lev);
-      SYS_ARCH_PROTECT(lev);
-      if (last_select_cb_ctr != select_cb_ctr) {
-        /* someone has changed select_cb_list, restart at the beginning */
-        scb = select_cb_list;
+      if (sock->errevent != 0) {
+        if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
+          do_signal = 1;
+        }
+      }
+      if (do_signal) {
+        scb->sem_signalled = 1;
+        /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
+           lead to the select thread taking itself off the list, invalidagin the semaphore. */
+        sys_sem_signal(&scb->sem);
       }
     }
-    if (scb) {
-      scb->sem_signalled = 1;
-      sys_sem_signal(&scb->sem);
-      SYS_ARCH_UNPROTECT(lev);
-    } else {
-      SYS_ARCH_UNPROTECT(lev);
-      break;
+    /* unlock interrupts with each step */
+    last_select_cb_ctr = select_cb_ctr;
+    SYS_ARCH_UNPROTECT(lev);
+    /* this makes sure interrupt protection time is short */
+    SYS_ARCH_PROTECT(lev);
+    if (last_select_cb_ctr != select_cb_ctr) {
+      /* someone has changed select_cb_list, restart at the beginning */
+      goto again;
     }
   }
+  SYS_ARCH_UNPROTECT(lev);
 }
 
 /**
@@ -1339,42 +1414,73 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
 int
 lwip_shutdown(int s, int how)
 {
-  LWIP_UNUSED_ARG(how);
+  struct lwip_sock *sock;
+  err_t err;
+  u8_t shut_rx = 0, shut_tx = 0;
+
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
-  return lwip_close(s); /* XXX temporary hack until proper implementation */
+
+  sock = get_socket(s);
+  if (!sock) {
+    return -1;
+  }
+
+  if (sock->conn != NULL) {
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
+      sock_set_errno(sock, EOPNOTSUPP);
+      return EOPNOTSUPP;
+    }
+  } else {
+    sock_set_errno(sock, ENOTCONN);
+    return ENOTCONN;
+  }
+
+  if (how == SHUT_RD) {
+    shut_rx = 1;
+  } else if (how == SHUT_WR) {
+    shut_tx = 1;
+  } else if(how == SHUT_RDWR) {
+    shut_rx = 1;
+    shut_tx = 1;
+  } else {
+    sock_set_errno(sock, EINVAL);
+    return EINVAL;
+  }
+  err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
+
+  sock_set_errno(sock, err_to_errno(err));
+  return (err == ERR_OK ? 0 : -1);
 }
 
 static int
 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
 {
   struct lwip_sock *sock;
-  struct sockaddr_in sin;
-  ip_addr_t naddr;
+  union sockaddr_aligned saddr;
+  ipX_addr_t naddr;
+  u16_t port;
 
   sock = get_socket(s);
   if (!sock) {
     return -1;
   }
 
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_len = sizeof(sin);
-  sin.sin_family = AF_INET;
-
   /* get the IP address and port */
-  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
+  /* @todo: this does not work for IPv6, yet */
+  netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local);
+  IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
+    &saddr, &naddr, port);
 
   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
-  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
-  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
-
-  sin.sin_port = htons(sin.sin_port);
-  inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
+  ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
+    SOCKETS_DEBUG, &naddr);
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
 
-  if (*namelen > sizeof(sin)) {
-    *namelen = sizeof(sin);
+  if (*namelen > saddr.sa.sa_len) {
+    *namelen = saddr.sa.sa_len;
   }
+  MEMCPY(name, &saddr, *namelen);
 
-  MEMCPY(name, &sin, *namelen);
   sock_set_errno(sock, 0);
   return 0;
 }
@@ -1448,7 +1554,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
         err = EINVAL;
       }
 #if LWIP_UDP
-      if ((sock->conn->type != NETCONN_UDP) ||
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP ||
           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
         /* this flag is only available for UDP, not for UDP lite */
         err = EAFNOSUPPORT;
@@ -1486,6 +1592,14 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
         err = EINVAL;
       }
       break;
+    case IP_MULTICAST_LOOP:
+      if (*optlen < sizeof(u8_t)) {
+        err = EINVAL;
+      }
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
+        err = EAFNOSUPPORT;
+      }
+      break;
 #endif /* LWIP_IGMP */
 
     default:
@@ -1504,7 +1618,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
     }
     
     /* If this is no TCP socket, ignore any options. */
-    if (sock->conn->type != NETCONN_TCP)
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
       return 0;
 
     switch (optname) {
@@ -1533,7 +1647,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
     }
     
     /* If this is no UDP lite socket, ignore any options. */
-    if (sock->conn->type != NETCONN_UDPLITE) {
+    if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
       return 0;
     }
 
@@ -1564,6 +1678,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
 
   /* Now do the actual option processing */
   data.sock = sock;
+#ifdef LWIP_DEBUG
+  data.s = s;
+#endif /* LWIP_DEBUG */
   data.level = level;
   data.optname = optname;
   data.optval = optval;
@@ -1601,7 +1718,7 @@ lwip_getsockopt_internal(void *arg)
   optval = data->optval;
 
   switch (level) {
-   
+
 /* Level: SOL_SOCKET */
   case SOL_SOCKET:
     switch (optname) {
@@ -1624,7 +1741,7 @@ lwip_getsockopt_internal(void *arg)
       break;
 
     case SO_TYPE:
-      switch (NETCONNTYPE_GROUP(sock->conn->type)) {
+      switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
       case NETCONN_RAW:
         *(int*)optval = SOCK_RAW;
         break;
@@ -1635,18 +1752,18 @@ lwip_getsockopt_internal(void *arg)
         *(int*)optval = SOCK_DGRAM;
         break;
       default: /* unrecognized socket type */
-        *(int*)optval = sock->conn->type;
+        *(int*)optval = netconn_type(sock->conn);
         LWIP_DEBUGF(SOCKETS_DEBUG,
                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
                     s, *(int *)optval));
-      }  /* switch (sock->conn->type) */
+      }  /* switch (netconn_type(sock->conn)) */
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
                   s, *(int *)optval));
       break;
 
     case SO_ERROR:
-      /* only overwrite if ERR_OK before */
-      if (sock->err == 0) {
+      /* only overwrite ERR_OK or tempoary errors */
+      if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
       } 
       *(int *)optval = sock->err;
@@ -1700,6 +1817,15 @@ lwip_getsockopt_internal(void *arg)
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
                   s, *(u32_t *)optval));
       break;
+    case IP_MULTICAST_LOOP:
+      if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
+        *(u8_t*)optval = 1;
+      } else {
+        *(u8_t*)optval = 0;
+      }
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
+                  s, *(int *)optval));
+      break;
 #endif /* LWIP_IGMP */
     default:
       LWIP_ASSERT("unhandled optname", 0);
@@ -1825,7 +1951,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
         err = EINVAL;
       }
 #if LWIP_UDP
-      if ((sock->conn->type != NETCONN_UDP) ||
+      if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) ||
           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
         /* this flag is only available for UDP, not for UDP lite */
         err = EAFNOSUPPORT;
@@ -1856,7 +1982,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
       if (optlen < sizeof(u8_t)) {
         err = EINVAL;
       }
-      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
         err = EAFNOSUPPORT;
       }
       break;
@@ -1864,7 +1990,15 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
       if (optlen < sizeof(struct in_addr)) {
         err = EINVAL;
       }
-      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
+        err = EAFNOSUPPORT;
+      }
+      break;
+    case IP_MULTICAST_LOOP:
+      if (optlen < sizeof(u8_t)) {
+        err = EINVAL;
+      }
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
         err = EAFNOSUPPORT;
       }
       break;
@@ -1873,7 +2007,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
       if (optlen < sizeof(struct ip_mreq)) {
         err = EINVAL;
       }
-      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
         err = EAFNOSUPPORT;
       }
       break;
@@ -1894,7 +2028,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
     }
 
     /* If this is no TCP socket, ignore any options. */
-    if (sock->conn->type != NETCONN_TCP)
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
       return 0;
 
     switch (optname) {
@@ -1923,7 +2057,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
     }
 
     /* If this is no UDP lite socket, ignore any options. */
-    if (sock->conn->type != NETCONN_UDPLITE)
+    if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn)))
       return 0;
 
     switch (optname) {
@@ -1954,6 +2088,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
 
   /* Now do the actual option processing */
   data.sock = sock;
+#ifdef LWIP_DEBUG
+  data.s = s;
+#endif /* LWIP_DEBUG */
   data.level = level;
   data.optname = optname;
   data.optval = (void*)optval;
@@ -2060,6 +2197,13 @@ lwip_setsockopt_internal(void *arg)
     case IP_MULTICAST_IF:
       inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
       break;
+    case IP_MULTICAST_LOOP:
+      if (*(u8_t*)optval) {
+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
+      } else {
+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
+      }
+      break;
     case IP_ADD_MEMBERSHIP:
     case IP_DROP_MEMBERSHIP:
       {
@@ -2169,21 +2313,49 @@ int
 lwip_ioctl(int s, long cmd, void *argp)
 {
   struct lwip_sock *sock = get_socket(s);
+  u8_t val;
+#if LWIP_SO_RCVBUF
   u16_t buflen = 0;
   s16_t recv_avail;
-  u8_t val;
+#endif /* LWIP_SO_RCVBUF */
 
   if (!sock) {
     return -1;
   }
 
   switch (cmd) {
+#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
   case FIONREAD:
     if (!argp) {
       sock_set_errno(sock, EINVAL);
       return -1;
     }
+#if LWIP_FIONREAD_LINUXMODE
+    if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
+      struct pbuf *p;
+      if (sock->lastdata) {
+        p = ((struct netbuf *)sock->lastdata)->p;
+      } else {
+        struct netbuf *rxbuf;
+        err_t err;
+        if (sock->rcvevent <= 0) {
+          *((u16_t*)argp) = 0;
+        } else {
+          err = netconn_recv(sock->conn, &rxbuf);
+          if (err != ERR_OK) {
+            *((u16_t*)argp) = 0;
+          } else {
+            sock->lastdata = rxbuf;
+            *((u16_t*)argp) = rxbuf->p->tot_len;
+          }
+        }
+      }
+      return 0;
+    }
+#endif /* LWIP_FIONREAD_LINUXMODE */
 
+#if LWIP_SO_RCVBUF
+    /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
     if (recv_avail < 0) {
       recv_avail = 0;
@@ -2193,7 +2365,7 @@ lwip_ioctl(int s, long cmd, void *argp)
     /* Check if there is data left from the last recv operation. /maq 041215 */
     if (sock->lastdata) {
       struct pbuf *p = (struct pbuf *)sock->lastdata;
-      if (netconn_type(sock->conn) != NETCONN_TCP) {
+      if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
         p = ((struct netbuf *)p)->p;
       }
       buflen = p->tot_len;
@@ -2205,6 +2377,10 @@ lwip_ioctl(int s, long cmd, void *argp)
     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
     sock_set_errno(sock, 0);
     return 0;
+#else /* LWIP_SO_RCVBUF */
+    break;
+#endif /* LWIP_SO_RCVBUF */
+#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
 
   case FIONBIO:
     val = 0;
@@ -2217,10 +2393,11 @@ lwip_ioctl(int s, long cmd, void *argp)
     return 0;
 
   default:
-    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
-    sock_set_errno(sock, ENOSYS); /* not yet implemented */
-    return -1;
+    break;
   } /* switch (cmd) */
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
+  sock_set_errno(sock, ENOSYS); /* not yet implemented */
+  return -1;
 }
 
 /** A minimal implementation of fcntl.
index 857e7d9bd640f038409fca3eaa4f8d36b8b04927..ef6fed5fc26b93837744c10c6b55fd422c179063 100644 (file)
@@ -103,6 +103,11 @@ tcpip_thread(void *arg)
         ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
       } else
 #endif /* LWIP_ETHERNET */
+#if LWIP_IPV6
+      if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) {
+          ip6_input(msg->msg.inp.p, msg->msg.inp.netif);
+      } else
+#endif /* LWIP_IPV6 */
       {
         ip_input(msg->msg.inp.p, msg->msg.inp.netif);
       }
@@ -117,12 +122,6 @@ tcpip_thread(void *arg)
       break;
 #endif /* LWIP_NETIF_API */
 
-    case TCPIP_MSG_CALLBACK:
-      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
-      msg->msg.cb.function(msg->msg.cb.ctx);
-      memp_free(MEMP_TCPIP_MSG_API, msg);
-      break;
-
 #if LWIP_TCPIP_TIMEOUT
     case TCPIP_MSG_TIMEOUT:
       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
@@ -136,6 +135,17 @@ tcpip_thread(void *arg)
       break;
 #endif /* LWIP_TCPIP_TIMEOUT */
 
+    case TCPIP_MSG_CALLBACK:
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
+      msg->msg.cb.function(msg->msg.cb.ctx);
+      memp_free(MEMP_TCPIP_MSG_API, msg);
+      break;
+
+    case TCPIP_MSG_CALLBACK_STATIC:
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
+      msg->msg.cb.function(msg->msg.cb.ctx);
+      break;
+
     default:
       LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
       LWIP_ASSERT("tcpip_thread: invalid message", 0);
@@ -172,22 +182,22 @@ tcpip_input(struct pbuf *p, struct netif *inp)
 #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
   struct tcpip_msg *msg;
 
-  if (sys_mbox_valid(&mbox)) {
-    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
-    if (msg == NULL) {
-      return ERR_MEM;
-    }
+  if (!sys_mbox_valid(&mbox)) {
+    return ERR_VAL;
+  }
+  msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
+  if (msg == NULL) {
+    return ERR_MEM;
+  }
 
-    msg->type = TCPIP_MSG_INPKT;
-    msg->msg.inp.p = p;
-    msg->msg.inp.netif = inp;
-    if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
-      memp_free(MEMP_TCPIP_MSG_INPKT, msg);
-      return ERR_MEM;
-    }
-    return ERR_OK;
+  msg->type = TCPIP_MSG_INPKT;
+  msg->msg.inp.p = p;
+  msg->msg.inp.netif = inp;
+  if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
+    memp_free(MEMP_TCPIP_MSG_INPKT, msg);
+    return ERR_MEM;
   }
-  return ERR_VAL;
+  return ERR_OK;
 #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
 }
 
@@ -392,6 +402,52 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
 #endif /* !LWIP_TCPIP_CORE_LOCKING */
 #endif /* LWIP_NETIF_API */
 
+/**
+ * Allocate a structure for a static callback message and initialize it.
+ * This is intended to be used to send "static" messages from interrupt context.
+ *
+ * @param function the function to call
+ * @param ctx parameter passed to function
+ * @return a struct pointer to pass to tcpip_trycallback().
+ */
+struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
+{
+  struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+  if (msg == NULL) {
+    return NULL;
+  }
+  msg->type = TCPIP_MSG_CALLBACK_STATIC;
+  msg->msg.cb.function = function;
+  msg->msg.cb.ctx = ctx;
+  return (struct tcpip_callback_msg*)msg;
+}
+
+/**
+ * Free a callback message allocated by tcpip_callbackmsg_new().
+ *
+ * @param msg the message to free
+ */
+void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
+{
+  memp_free(MEMP_TCPIP_MSG_API, msg);
+}
+
+/**
+ * Try to post a callback-message to the tcpip_thread mbox
+ * This is intended to be used to send "static" messages from interrupt context.
+ *
+ * @param msg pointer to the message to post
+ * @return sys_mbox_trypost() return code
+ */
+err_t
+tcpip_trycallback(struct tcpip_callback_msg* msg)
+{
+  if (!sys_mbox_valid(&mbox)) {
+    return ERR_VAL;
+  }
+  return sys_mbox_trypost(&mbox, msg);
+}
+
 /**
  * Initialize this module:
  * - initialize all sub modules
index 68bfd26325611d102b931fdea3a0f990569e2c6b..fe85a7e8de2004e29642e81f55d464194b15e7c8 100644 (file)
@@ -76,7 +76,6 @@
 #include "lwip/ip_addr.h"
 #include "lwip/netif.h"
 #include "lwip/def.h"
-#include "lwip/sys.h"
 #include "lwip/dhcp.h"
 #include "lwip/autoip.h"
 #include "lwip/dns.h"
 #define DHCP_OPTION_IDX_T2          5
 #define DHCP_OPTION_IDX_SUBNET_MASK 6
 #define DHCP_OPTION_IDX_ROUTER      7
-#define DHCP_OPTION_IDX_DNS_SERVER     8
+#define DHCP_OPTION_IDX_DNS_SERVER  8
 #define DHCP_OPTION_IDX_MAX         (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)
 
 /** Holds the decoded option values, only valid while in dhcp_recv.
@@ -126,6 +125,11 @@ u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];
     @todo: move this into struct dhcp? */
 u8_t  dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];
 
+#ifdef DHCP_GLOBAL_XID
+static u32_t xid;
+static u8_t xid_initialised;
+#endif /* DHCP_GLOBAL_XID */
+
 #define dhcp_option_given(dhcp, idx)          (dhcp_rx_options_given[idx] != 0)
 #define dhcp_got_option(dhcp, idx)            (dhcp_rx_options_given[idx] = 1)
 #define dhcp_clear_option(dhcp, idx)          (dhcp_rx_options_given[idx] = 0)
@@ -301,11 +305,11 @@ dhcp_select(struct netif *netif)
       if (namelen > 0) {
         LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
         dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
-      while (*p) {
-        dhcp_option_byte(dhcp, *p++);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
       }
     }
-    }
 #endif /* LWIP_NETIF_HOSTNAME */
 
     dhcp_option_trailer(dhcp);
@@ -569,7 +573,7 @@ dhcp_handle_ack(struct netif *netif)
     ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
     dns_setserver(n, &dns_addr);
     n++;
-    }
+  }
 #endif /* LWIP_DNS */
 }
 
@@ -592,6 +596,23 @@ dhcp_set_struct(struct netif *netif, struct dhcp *dhcp)
   netif->dhcp = dhcp;
 }
 
+/** Removes a struct dhcp from a netif.
+ *
+ * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the
+ *            struct dhcp since the memory is passed back to the heap.
+ *
+ * @param netif the netif from which to remove the struct dhcp
+ */
+void dhcp_cleanup(struct netif *netif)
+{
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+
+  if (netif->dhcp != NULL) {
+    mem_free(netif->dhcp);
+    netif->dhcp = NULL;
+  }
+}
+
 /**
  * Start DHCP negotiation for a network interface.
  *
@@ -706,12 +727,12 @@ dhcp_inform(struct netif *netif)
     pcb = udp_new();
     if (pcb == NULL) {
       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb"));
-    return;
-  }
+      return;
+    }
     dhcp.pcb = pcb;
     dhcp.pcb->so_options |= SOF_BROADCAST;
     udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
-  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
   }
   /* create and initialize the DHCP message header */
   result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM);
@@ -761,6 +782,12 @@ dhcp_network_changed(struct netif *netif)
     break;
   default:
     dhcp->tries = 0;
+#if LWIP_DHCP_AUTOIP_COOP
+    if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
+      autoip_stop(netif);
+      dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
+    }
+#endif /* LWIP_DHCP_AUTOIP_COOP */
     dhcp_discover(netif);
     break;
   }
@@ -942,11 +969,11 @@ dhcp_bind(struct netif *netif)
     /* subnet mask not given, choose a safe subnet mask given the network class */
     u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);
     if (first_octet <= 127) {
-      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000));
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL));
     } else if (first_octet >= 192) {
-      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00));
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL));
     } else {
-      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000));
+      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL));
     }
   }
 
@@ -956,7 +983,7 @@ dhcp_bind(struct netif *netif)
     /* copy network address */
     ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);
     /* use first host address on network as gateway */
-    ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001));
+    ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL));
   }
 
 #if LWIP_DHCP_AUTOIP_COOP
@@ -1008,11 +1035,11 @@ dhcp_renew(struct netif *netif)
       if (namelen > 0) {
         LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
         dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
-      while (*p) {
-        dhcp_option_byte(dhcp, *p++);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
       }
     }
-    }
 #endif /* LWIP_NETIF_HOSTNAME */
 
 #if 0
@@ -1071,11 +1098,11 @@ dhcp_rebind(struct netif *netif)
       if (namelen > 0) {
         LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255);
         dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);
-      while (*p) {
-        dhcp_option_byte(dhcp, *p++);
+        while (*p) {
+          dhcp_option_byte(dhcp, *p++);
+        }
       }
     }
-    }
 #endif /* LWIP_NETIF_HOSTNAME */
 
 #if 0
@@ -1206,8 +1233,9 @@ dhcp_release(struct netif *netif)
 void
 dhcp_stop(struct netif *netif)
 {
-  struct dhcp *dhcp = netif->dhcp;
+  struct dhcp *dhcp;
   LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
+  dhcp = netif->dhcp;
   /* Remove the flag that says this netif is handled by DHCP. */
   netif->flags &= ~NETIF_FLAG_DHCP;
 
@@ -1215,10 +1243,10 @@ dhcp_stop(struct netif *netif)
   /* netif is DHCP configured? */
   if (dhcp != NULL) {
 #if LWIP_DHCP_AUTOIP_COOP
-  if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
-    autoip_stop(netif);
-    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
-  }
+    if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
+      autoip_stop(netif);
+      dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
+    }
 #endif /* LWIP_DHCP_AUTOIP_COOP */
 
     if (dhcp->pcb != NULL) {
@@ -1430,16 +1458,17 @@ decode_next:
         value = ntohl(value);
       } else {
         LWIP_ASSERT("invalid decode_len", decode_len == 1);
-  }
-        dhcp_got_option(dhcp, decode_idx);
-        dhcp_set_option_value(dhcp, decode_idx, value);
-  }
+        value = ((u8_t*)&value)[0];
+      }
+      dhcp_got_option(dhcp, decode_idx);
+      dhcp_set_option_value(dhcp, decode_idx, value);
+    }
     if (offset >= q->len) {
       offset -= q->len;
       offset_max -= q->len;
       q = q->next;
       options = (u8_t*)q->payload;
-  }
+    }
   }
   /* is this an overloaded message? */
   if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {
@@ -1457,7 +1486,7 @@ decode_next:
       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n"));
     } else {
       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload));
-  }
+    }
 #if LWIP_DHCP_BOOTP_FILE
     if (!parse_file_as_options) {
       /* only do this for ACK messages */
@@ -1603,8 +1632,6 @@ dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)
    *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
   static u32_t xid = 0xABCD0000;
 #else
-  static u32_t xid;
-  static u8_t xid_initialised = 0;
   if (!xid_initialised) {
     xid = DHCP_GLOBAL_XID;
     xid_initialised = !xid_initialised;
index c3f356cfceace02605bcf27e4e660605b42d7cb5..d63361226f2e793478f71798bbc6bf7aa074a1a4 100644 (file)
@@ -635,7 +635,7 @@ dns_send(u8_t numdns, const char* name, u8_t id)
 static void
 dns_check_entry(u8_t i)
 {
-  int err;
+  err_t err;
   struct dns_table_entry *pEntry = &dns_table[i];
 
   LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
@@ -648,11 +648,13 @@ dns_check_entry(u8_t i)
       pEntry->numdns  = 0;
       pEntry->tmr     = 1;
       pEntry->retries = 0;
-
+      
       /* send DNS packet for this entry */
       err = dns_send(pEntry->numdns, pEntry->name, i);
-      if (err)
-        printf("Error in dns_send: %d\n", err);
+      if (err != ERR_OK) {
+        LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                    ("dns_send returned error: %s\n", lwip_strerr(err)));
+      }
       break;
     }
 
@@ -682,8 +684,10 @@ dns_check_entry(u8_t i)
 
         /* send DNS packet for this entry */
         err = dns_send(pEntry->numdns, pEntry->name, i);
-        if (err)
-          printf("Error in dns_send: %d\n", err);
+        if (err != ERR_OK) {
+          LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
+                      ("dns_send returned error: %s\n", lwip_strerr(err)));
+        }
       }
       break;
     }
@@ -918,6 +922,7 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
  *   name is already in the local names table.
  * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
  *   for resolution if no errors are present.
+ * - ERR_ARG: dns client not initialized or invalid hostname
  *
  * @param hostname the hostname that is to be queried
  * @param addr pointer to a ip_addr_t where to store the address if it is already
@@ -937,7 +942,7 @@ dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback foun
   if ((dns_pcb == NULL) || (addr == NULL) ||
       (!hostname) || (!hostname[0]) ||
       (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
-    return ERR_VAL;
+    return ERR_ARG;
   }
 
 #if LWIP_HAVE_LOOPIF
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/inet_chksum.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/inet_chksum.c
new file mode 100644 (file)
index 0000000..8bc42c1
--- /dev/null
@@ -0,0 +1,545 @@
+/**
+ * @file
+ * Incluse internet checksum functions.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+
+#include "lwip/inet_chksum.h"
+#include "lwip/def.h"
+
+#include <stddef.h>
+#include <string.h>
+
+/* These are some reference implementations of the checksum algorithm, with the
+ * aim of being simple, correct and fully portable. Checksumming is the
+ * first thing you would want to optimize for your platform. If you create
+ * your own version, link it in and in your cc.h put:
+ * 
+ * #define LWIP_CHKSUM <your_checksum_routine> 
+ *
+ * Or you can select from the implementations below by defining
+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
+ */
+
+#ifndef LWIP_CHKSUM
+# define LWIP_CHKSUM lwip_standard_chksum
+# ifndef LWIP_CHKSUM_ALGORITHM
+#  define LWIP_CHKSUM_ALGORITHM 2
+# endif
+u16_t lwip_standard_chksum(void *dataptr, int len);
+#endif
+/* If none set: */
+#ifndef LWIP_CHKSUM_ALGORITHM
+# define LWIP_CHKSUM_ALGORITHM 0
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
+/**
+ * lwip checksum
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ *
+ * @note accumulator size limits summable length to 64k
+ * @note host endianess is irrelevant (p3 RFC1071)
+ */
+u16_t
+lwip_standard_chksum(void *dataptr, u16_t len)
+{
+  u32_t acc;
+  u16_t src;
+  u8_t *octetptr;
+
+  acc = 0;
+  /* dataptr may be at odd or even addresses */
+  octetptr = (u8_t*)dataptr;
+  while (len > 1) {
+    /* declare first octet as most significant
+       thus assume network order, ignoring host order */
+    src = (*octetptr) << 8;
+    octetptr++;
+    /* declare second octet as least significant */
+    src |= (*octetptr);
+    octetptr++;
+    acc += src;
+    len -= 2;
+  }
+  if (len > 0) {
+    /* accumulate remaining octet */
+    src = (*octetptr) << 8;
+    acc += src;
+  }
+  /* add deferred carry bits */
+  acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  if ((acc & 0xffff0000UL) != 0) {
+    acc = (acc >> 16) + (acc & 0x0000ffffUL);
+  }
+  /* This maybe a little confusing: reorder sum using htons()
+     instead of ntohs() since it has a little less call overhead.
+     The caller must invert bits for Internet sum ! */
+  return htons((u16_t)acc);
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
+/*
+ * Curt McDowell
+ * Broadcom Corp.
+ * csm@broadcom.com
+ *
+ * IP checksum two bytes at a time with support for
+ * unaligned buffer.
+ * Works for len up to and including 0x20000.
+ * by Curt McDowell, Broadcom Corp. 12/08/2005
+ *
+ * @param dataptr points to start of data to be summed at any boundary
+ * @param len length of data to be summed
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ */
+
+u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t sum = 0;
+  int odd = ((mem_ptr_t)pb & 1);
+
+  /* Get aligned to u16_t */
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  /* Add the bulk of the data */
+  ps = (u16_t *)(void *)pb;
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* Consume left-over byte, if any */
+  if (len > 0) {
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  /* Add end bytes */
+  sum += t;
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  /* Swap if alignment was odd */
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
+/**
+ * An optimized checksum routine. Basically, it uses loop-unrolling on
+ * the checksum loop, treating the head and tail bytes specially, whereas
+ * the inner loop acts on 8 bytes at a time. 
+ *
+ * @arg start of buffer to be checksummed. May be an odd byte address.
+ * @len number of bytes in the buffer to be checksummed.
+ * @return host order (!) lwip checksum (non-inverted Internet sum) 
+ * 
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005
+ */
+
+u16_t
+lwip_standard_chksum(void *dataptr, int len)
+{
+  u8_t *pb = (u8_t *)dataptr;
+  u16_t *ps, t = 0;
+  u32_t *pl;
+  u32_t sum = 0, tmp;
+  /* starts at odd byte address? */
+  int odd = ((mem_ptr_t)pb & 1);
+
+  if (odd && len > 0) {
+    ((u8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  ps = (u16_t *)pb;
+
+  if (((mem_ptr_t)ps & 3) && len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  pl = (u32_t *)ps;
+
+  while (len > 7)  {
+    tmp = sum + *pl++;          /* ping */
+    if (tmp < sum) {
+      tmp++;                    /* add back carry */
+    }
+
+    sum = tmp + *pl++;          /* pong */
+    if (sum < tmp) {
+      sum++;                    /* add back carry */
+    }
+
+    len -= 8;
+  }
+
+  /* make room in upper bits */
+  sum = FOLD_U32T(sum);
+
+  ps = (u16_t *)pl;
+
+  /* 16-bit aligned word remaining? */
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* dangling tail byte remaining? */
+  if (len > 0) {                /* include odd byte */
+    ((u8_t *)&t)[0] = *(u8_t *)ps;
+  }
+
+  sum += t;                     /* add end bytes */
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  if (odd) {
+    sum = SWAP_BYTES_IN_WORD(sum);
+  }
+
+  return (u16_t)sum;
+}
+#endif
+
+/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
+static u16_t
+inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
+{
+  struct pbuf *q;
+  u8_t swapped = 0;
+
+  /* iterate through all pbuf in chain */
+  for(q = p; q != NULL; q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* just executing this next line is probably faster that the if statement needed
+       to check whether we really need to execute it, and does no harm */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum_pseudo:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
+       ip_addr_t *src, ip_addr_t *dest)
+{
+  u32_t acc;
+  u32_t addr;
+
+  addr = ip4_addr_get_u32(src);
+  acc = (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  /* fold down to 16 bits */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+
+  return inet_cksum_pseudo_base(p, proto, proto_len, acc);
+}
+#if LWIP_IPV6
+/**
+ * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
+ * IPv6 addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ipv6 address (used for checksum of pseudo header)
+ * @param dst destination ipv6 address (used for checksum of pseudo header)
+ * @param proto ipv6 protocol/next header (used for checksum of pseudo header)
+ * @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
+       ip6_addr_t *src, ip6_addr_t *dest)
+{
+  u32_t acc = 0;
+  u32_t addr;
+  u8_t addr_part;
+
+  for (addr_part = 0; addr_part < 4; addr_part++) {
+    addr = src->addr[addr_part];
+    acc += (addr & 0xffffUL);
+    acc += ((addr >> 16) & 0xffffUL);
+    addr = dest->addr[addr_part];
+    acc += (addr & 0xffffUL);
+    acc += ((addr >> 16) & 0xffffUL);
+  }
+  /* fold down to 16 bits */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+
+  return inet_cksum_pseudo_base(p, proto, proto_len, acc);
+}
+#endif /* LWIP_IPV6 */
+
+/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
+static u16_t
+inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
+       u16_t chksum_len, u32_t acc)
+{
+  struct pbuf *q;
+  u8_t swapped = 0;
+  u16_t chklen;
+
+  /* iterate through all pbuf in chain */
+  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
+      (void *)q, (void *)q->next));
+    chklen = q->len;
+    if (chklen > chksum_len) {
+      chklen = chksum_len;
+    }
+    acc += LWIP_CHKSUM(q->payload, chklen);
+    chksum_len -= chklen;
+    LWIP_ASSERT("delete me", chksum_len < 0x7fff);
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
+    /* fold the upper bit down */
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+
+  acc += (u32_t)htons((u16_t)proto);
+  acc += (u32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* inet_chksum_pseudo_partial:
+ *
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
+ * IP addresses are expected to be in network byte order.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ip address (used for checksum of pseudo header)
+ * @param dst destination ip address (used for checksum of pseudo header)
+ * @param proto ip protocol (used for checksum of pseudo header)
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
+       u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest)
+{
+  u32_t acc;
+  u32_t addr;
+
+  addr = ip4_addr_get_u32(src);
+  acc = (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = ip4_addr_get_u32(dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  /* fold down to 16 bits */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+
+  return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
+}
+
+#if LWIP_IPV6
+/**
+ * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
+ * IPv6 addresses are expected to be in network byte order. Will only compute for a
+ * portion of the payload.
+ *
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)
+ * @param src source ipv6 address (used for checksum of pseudo header)
+ * @param dst destination ipv6 address (used for checksum of pseudo header)
+ * @param proto ipv6 protocol/next header (used for checksum of pseudo header)
+ * @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
+ * @param chksum_len number of payload bytes used to compute chksum
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
+       u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest)
+{
+  u32_t acc = 0;
+  u32_t addr;
+  u8_t addr_part;
+
+  for (addr_part = 0; addr_part < 4; addr_part++) {
+    addr = src->addr[addr_part];
+    acc += (addr & 0xffffUL);
+    acc += ((addr >> 16) & 0xffffUL);
+    addr = dest->addr[addr_part];
+    acc += (addr & 0xffffUL);
+    acc += ((addr >> 16) & 0xffffUL);
+  }
+  /* fold down to 16 bits */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+
+  return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
+}
+#endif /* LWIP_IPV6 */
+
+/* inet_chksum:
+ *
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP
+ * and ICMP.
+ *
+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)
+ * @param len length of the buffer to calculate the checksum
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+
+u16_t
+inet_chksum(void *dataptr, u16_t len)
+{
+  return ~LWIP_CHKSUM(dataptr, len);
+}
+
+/**
+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
+ * inet_chksum only pbufs are used).
+ *
+ * @param p pbuf chain over that the checksum should be calculated
+ * @return checksum (as u16_t) to be saved directly in the protocol header
+ */
+u16_t
+inet_chksum_pbuf(struct pbuf *p)
+{
+  u32_t acc;
+  struct pbuf *q;
+  u8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  for(q = p; q != NULL; q = q->next) {
+    acc += LWIP_CHKSUM(q->payload, q->len);
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = SWAP_BYTES_IN_WORD(acc);
+    }
+  }
+
+  if (swapped) {
+    acc = SWAP_BYTES_IN_WORD(acc);
+  }
+  return (u16_t)~(acc & 0xffffUL);
+}
+
+/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
+ * like MEMCPY but generates a checksum at the same time. Since this is a
+ * performance-sensitive function, you might want to create your own version
+ * in assembly targeted at your hardware by defining it in lwipopts.h:
+ *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
+ */
+
+#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
+/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
+ * For architectures with big caches, data might still be in cache when
+ * generating the checksum after copying.
+ */
+u16_t
+lwip_chksum_copy(void *dst, const void *src, u16_t len)
+{
+  MEMCPY(dst, src, len);
+  return LWIP_CHKSUM(dst, len);
+}
+#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */
index 5763f104899eabaf62c47a973167fe096a37cdb4..3d8e2bb6a554c12471149a74cb12a32f2fc373a5 100644 (file)
 #include "lwip/dns.h"
 #include "lwip/timers.h"
 #include "netif/etharp.h"
+#include "lwip/ip6.h"
+#include "lwip/nd6.h"
+#include "lwip/mld6.h"
+#include "lwip/api.h"
 
 /* Compile-time sanity checks for configuration errors.
  * These can be done independently of LWIP_DEBUG, without penalty.
 #if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
   #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
 #endif
+#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
+  #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
+#endif
 #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
   #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
 #endif
   #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
 #endif
 /* There must be sufficient timeouts, taking into account requirements of the subsystems. */
-#if (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
+#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
   #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
 #endif
 #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
 #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
   #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
 #endif
-#if LWIP_IGMP && !defined(LWIP_RAND)
-  #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
+#if (LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
+  #error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
 #endif
 #if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
   #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
 #if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
   #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
 #endif
+#if LWIP_NETCONN && LWIP_TCP
+#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
+  #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
+#endif
+#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
+  #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
+#endif
+#endif /* LWIP_NETCONN && LWIP_TCP */ 
+#if LWIP_SOCKET
+/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
+#if SO_ACCEPTCONN != SOF_ACCEPTCONN
+  #error "SO_ACCEPTCONN != SOF_ACCEPTCONN"
+#endif
+#if SO_REUSEADDR != SOF_REUSEADDR
+  #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
+#endif
+#if SO_KEEPALIVE != SOF_KEEPALIVE
+  #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE"
+#endif
+#if SO_BROADCAST != SOF_BROADCAST
+  #error "WARNING: SO_BROADCAST != SOF_BROADCAST"
+#endif
+#if SO_LINGER != SOF_LINGER
+  #error "WARNING: SO_LINGER != SOF_LINGER"
+#endif
+#endif /* LWIP_SOCKET */
 
 
 /* Compile-time checks for deprecated options.
@@ -232,19 +265,6 @@ lwip_sanity_check(void)
   if (TCP_WND < TCP_MSS)
     LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
 #endif /* LWIP_TCP */
-#if LWIP_SOCKET
-  /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
-  if (SO_ACCEPTCONN != SOF_ACCEPTCONN)
-    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n"));
-  if (SO_REUSEADDR != SOF_REUSEADDR)
-    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n"));
-  if (SO_KEEPALIVE != SOF_KEEPALIVE)
-    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n"));
-  if (SO_BROADCAST != SOF_BROADCAST)
-    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n"));
-  if (SO_LINGER != SOF_LINGER)
-    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n"));
-#endif /* LWIP_SOCKET */
 }
 #else  /* LWIP_DEBUG */
 #define lwip_sanity_check()
@@ -261,7 +281,9 @@ lwip_init(void)
 
   /* Modules initialization */
   stats_init();
+#if !NO_SYS
   sys_init();
+#endif /* !NO_SYS */
   mem_init();
   memp_init();
   pbuf_init();
@@ -294,6 +316,15 @@ lwip_init(void)
 #if LWIP_DNS
   dns_init();
 #endif /* LWIP_DNS */
+#if LWIP_IPV6
+  ip6_init();
+  nd6_init();
+#if LWIP_IPV6_MLD
+  mld6_init();
+#endif /* LWIP_IPV6_MLD */
+#endif /* LWIP_IPV6 */
 
+#if LWIP_TIMERS
   sys_timeouts_init();
+#endif /* LWIP_TIMERS */
 }
index a26c39464359a494333705391cfb079c9a035d38..b122da27e3ff57731c03744603208a4c53fbfdc0 100644 (file)
@@ -122,14 +122,6 @@ static err_t autoip_bind(struct netif *netif);
 /* start sending probes for llipaddr */
 static void autoip_start_probing(struct netif *netif);
 
-/**
- * Initialize this module
- */
-void
-autoip_init(void)
-{
-  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
-}
 
 /** Set a statically allocated struct autoip to work with.
  * Using this prevents autoip_start to allocate it using mem_malloc.
@@ -150,6 +142,17 @@ autoip_set_struct(struct netif *netif, struct autoip *autoip)
   netif->autoip = autoip;
 }
 
+/** Restart AutoIP client and check the next address (conflict detected)
+ *
+ * @param netif The netif under AutoIP control
+ */
+static void
+autoip_restart(struct netif *netif)
+{
+  netif->autoip->tried_llipaddr++;
+  autoip_start(netif);
+}
+
 /**
  * Handle a IP address conflict after an ARP conflict detection
  */
@@ -159,8 +162,8 @@ autoip_handle_arp_conflict(struct netif *netif)
   /* Somehow detect if we are defending or retreating */
   unsigned char defend = 1; /* tbd */
 
-  if(defend) {
-    if(netif->autoip->lastconflict > 0) {
+  if (defend) {
+    if (netif->autoip->lastconflict > 0) {
       /* retreat, there was a conflicting ARP in the last
        * DEFEND_INTERVAL seconds
        */
@@ -168,7 +171,7 @@ autoip_handle_arp_conflict(struct netif *netif)
         ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
 
       /* TODO: close all TCP sessions */
-      autoip_start(netif);
+      autoip_restart(netif);
     } else {
       LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
         ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
@@ -179,7 +182,7 @@ autoip_handle_arp_conflict(struct netif *netif)
     LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
       ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
     /* TODO: close all TCP sessions */
-    autoip_start(netif);
+    autoip_restart(netif);
   }
 }
 
@@ -208,7 +211,7 @@ autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
     addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
   }
   LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
-       (addr <= AUTOIP_RANGE_END));
+    (addr <= AUTOIP_RANGE_END));
   ip4_addr_set_u32(ipaddr, htonl(addr));
   
   LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
@@ -284,7 +287,7 @@ autoip_start(struct netif *netif)
   struct autoip *autoip = netif->autoip;
   err_t result = ERR_OK;
 
-  if(netif_is_up(netif)) {
+  if (netif_is_up(netif)) {
     netif_set_down(netif);
   }
 
@@ -298,17 +301,17 @@ autoip_start(struct netif *netif)
   LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
     ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
     netif->name[1], (u16_t)netif->num));
-  if(autoip == NULL) {
+  if (autoip == NULL) {
     /* no AutoIP client attached yet? */
     LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
       ("autoip_start(): starting new AUTOIP client\n"));
     autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
-    if(autoip == NULL) {
+    if (autoip == NULL) {
       LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
         ("autoip_start(): could not allocate autoip\n"));
       return ERR_MEM;
     }
-    memset( autoip, 0, sizeof(struct autoip));
+    memset(autoip, 0, sizeof(struct autoip));
     /* store this AutoIP client in the netif */
     netif->autoip = autoip;
     LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
@@ -316,12 +319,11 @@ autoip_start(struct netif *netif)
     autoip->state = AUTOIP_STATE_OFF;
     autoip->ttw = 0;
     autoip->sent_num = 0;
-    memset(&autoip->llipaddr, 0, sizeof(ip_addr_t));
+    ip_addr_set_zero(&autoip->llipaddr);
     autoip->lastconflict = 0;
   }
 
   autoip_create_addr(netif, &(autoip->llipaddr));
-  autoip->tried_llipaddr++;
   autoip_start_probing(netif);
 
   return result;
@@ -350,7 +352,7 @@ autoip_start_probing(struct netif *netif)
    * accquiring and probing address
    * compliant to RFC 3927 Section 2.2.1
    */
-  if(autoip->tried_llipaddr > MAX_CONFLICTS) {
+  if (autoip->tried_llipaddr > MAX_CONFLICTS) {
     autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
   }
 }
@@ -394,7 +396,7 @@ autoip_tmr()
   while (netif != NULL) {
     /* only act on AutoIP configured interfaces */
     if (netif->autoip != NULL) {
-      if(netif->autoip->lastconflict > 0) {
+      if (netif->autoip->lastconflict > 0) {
         netif->autoip->lastconflict--;
       }
 
@@ -404,10 +406,10 @@ autoip_tmr()
 
       switch(netif->autoip->state) {
         case AUTOIP_STATE_PROBING:
-          if(netif->autoip->ttw > 0) {
+          if (netif->autoip->ttw > 0) {
             netif->autoip->ttw--;
           } else {
-            if(netif->autoip->sent_num >= PROBE_NUM) {
+            if (netif->autoip->sent_num >= PROBE_NUM) {
               netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
               netif->autoip->sent_num = 0;
               netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
@@ -429,10 +431,10 @@ autoip_tmr()
           break;
 
         case AUTOIP_STATE_ANNOUNCING:
-          if(netif->autoip->ttw > 0) {
+          if (netif->autoip->ttw > 0) {
             netif->autoip->ttw--;
           } else {
-            if(netif->autoip->sent_num == 0) {
+            if (netif->autoip->sent_num == 0) {
              /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
               * Now we can bind to an IP address and use it.
               *
@@ -448,10 +450,10 @@ autoip_tmr()
             netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
             netif->autoip->sent_num++;
 
-            if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
-              netif->autoip->state = AUTOIP_STATE_BOUND;
-              netif->autoip->sent_num = 0;
-              netif->autoip->ttw = 0;
+            if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
+                netif->autoip->state = AUTOIP_STATE_BOUND;
+                netif->autoip->sent_num = 0;
+                netif->autoip->ttw = 0;
                  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
                     ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
                      ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
@@ -484,12 +486,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
     */
     ip_addr_t sipaddr, dipaddr;
     struct eth_addr netifaddr;
-    netifaddr.addr[0] = netif->hwaddr[0];
-    netifaddr.addr[1] = netif->hwaddr[1];
-    netifaddr.addr[2] = netif->hwaddr[2];
-    netifaddr.addr[3] = netif->hwaddr[3];
-    netifaddr.addr[4] = netif->hwaddr[4];
-    netifaddr.addr[5] = netif->hwaddr[5];
+    ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
 
     /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
      * structure packing (not using structure copy which breaks strict-aliasing rules).
@@ -511,7 +508,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
            !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
         LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
           ("autoip_arp_reply(): Probe Conflict detected\n"));
-        autoip_start(netif);
+        autoip_restart(netif);
       }
     } else {
      /* RFC 3927 Section 2.5:
index e12a0e17627c23762f9450ceffcf167e167d0094..ca59acfc093ec9c963e9dae77a1b3f830d730781 100644 (file)
@@ -70,7 +70,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
  * Currently only processes icmp echo requests and sends
  * out the echo response.
  *
- * @param p the icmp echo request packet, p->payload pointing to the ip header
+ * @param p the icmp echo request packet, p->payload pointing to the icmp header
  * @param inp the netif on which this packet was received
  */
 void
@@ -82,16 +82,14 @@ icmp_input(struct pbuf *p, struct netif *inp)
 #endif /* LWIP_DEBUG */
   struct icmp_echo_hdr *iecho;
   struct ip_hdr *iphdr;
-  ip_addr_t tmpaddr;
   s16_t hlen;
 
   ICMP_STATS_INC(icmp.recv);
   snmp_inc_icmpinmsgs();
 
-
-  iphdr = (struct ip_hdr *)p->payload;
+  iphdr = (struct ip_hdr *)ip_current_header();
   hlen = IPH_HL(iphdr) * 4;
-  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
+  if (p->len < sizeof(u16_t)*2) {
     LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
     goto lenerr;
   }
@@ -111,13 +109,13 @@ icmp_input(struct pbuf *p, struct netif *inp)
       int accepted = 1;
 #if !LWIP_MULTICAST_PING
       /* multicast destination address? */
-      if (ip_addr_ismulticast(&iphdr->dest)) {
+      if (ip_addr_ismulticast(ip_current_dest_addr())) {
         accepted = 0;
       }
 #endif /* LWIP_MULTICAST_PING */
 #if !LWIP_BROADCAST_PING
       /* broadcast destination address? */
-      if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
+      if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
         accepted = 0;
       }
 #endif /* LWIP_BROADCAST_PING */
@@ -188,12 +186,11 @@ icmp_input(struct pbuf *p, struct netif *inp)
     /* We generate an answer by switching the dest and src ip addresses,
      * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
     iecho = (struct icmp_echo_hdr *)p->payload;
-    ip_addr_copy(tmpaddr, iphdr->src);
-    ip_addr_copy(iphdr->src, iphdr->dest);
-    ip_addr_copy(iphdr->dest, tmpaddr);
+    ip_addr_copy(iphdr->src, *ip_current_dest_addr());
+    ip_addr_copy(iphdr->dest, *ip_current_src_addr());
     ICMPH_TYPE_SET(iecho, ICMP_ER);
     /* adjust the checksum */
-    if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {
+    if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
       iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
     } else {
       iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
@@ -216,7 +213,8 @@ icmp_input(struct pbuf *p, struct netif *inp)
       LWIP_ASSERT("Can't move over header in packet", 0);
     } else {
       err_t ret;
-      ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
+      /* send an ICMP packet, src addr is the dest addr of the curren packet */
+      ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
                    ICMP_TTL, 0, IP_PROTO_ICMP, inp);
       if (ret != ERR_OK) {
         LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
@@ -291,6 +289,7 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
   struct ip_hdr *iphdr;
   /* we can use the echo header here */
   struct icmp_echo_hdr *icmphdr;
+  ip_addr_t iphdr_src;
 
   /* ICMP header + IP header + 8 bytes of data */
   q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
@@ -327,7 +326,8 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
   snmp_inc_icmpoutmsgs();
   /* increase number of destination unreachable messages attempted to send */
   snmp_inc_icmpouttimeexcds();
-  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
+  ip_addr_copy(iphdr_src, iphdr->src);
+  ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
   pbuf_free(q);
 }
 
index 2a1dd82dc0efeace5ba53654b5fcc5f78d64e614..22a1e1619d518fdf8e46d2e0a82822b04bfca349 100644 (file)
@@ -100,7 +100,7 @@ Steve Reynolds
  */
 #define IGMP_TTL                       1
 #define IGMP_MINLEN                    8
-#define ROUTER_ALERT                   0x9404
+#define ROUTER_ALERT                   0x9404U
 #define ROUTER_ALERTLEN                4
 
 /*
@@ -127,7 +127,7 @@ struct igmp_msg {
  PACK_STRUCT_FIELD(u8_t           igmp_msgtype);
  PACK_STRUCT_FIELD(u8_t           igmp_maxresp);
  PACK_STRUCT_FIELD(u16_t          igmp_checksum);
- PACK_STRUCT_FIELD(ip_addr_t      igmp_group_address);
+ PACK_STRUCT_FIELD(ip_addr_p_t    igmp_group_address);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
 #ifdef PACK_STRUCT_USE_INCLUDES
@@ -139,7 +139,6 @@ static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
 static err_t  igmp_remove_group(struct igmp_group *group);
 static void   igmp_timeout( struct igmp_group *group);
 static void   igmp_start_timer(struct igmp_group *group, u8_t max_time);
-static void   igmp_stop_timer(struct igmp_group *group);
 static void   igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
 static err_t  igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
 static void   igmp_send(struct igmp_group *group, u8_t type);
@@ -326,7 +325,7 @@ igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
   }
 
   /* Group doesn't exist yet, create a new one */
-  group = memp_malloc(MEMP_IGMP_GROUP);
+  group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
   if (group != NULL) {
     group->netif              = ifp;
     ip_addr_set(&(group->group_address), addr);
@@ -382,14 +381,13 @@ igmp_remove_group(struct igmp_group *group)
 /**
  * Called from ip_input() if a new IGMP packet is received.
  *
- * @param p received igmp packet, p->payload pointing to the ip header
+ * @param p received igmp packet, p->payload pointing to the igmp header
  * @param inp network interface on which the packet was received
  * @param dest destination ip address of the igmp packet
  */
 void
 igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
 {
-  struct ip_hdr *    iphdr;
   struct igmp_msg*   igmp;
   struct igmp_group* group;
   struct igmp_group* groupref;
@@ -397,8 +395,7 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
   IGMP_STATS_INC(igmp.recv);
 
   /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    
-  iphdr = p->payload;
-  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
+  if (p->len < IGMP_MINLEN) {
     pbuf_free(p);
     IGMP_STATS_INC(igmp.lenerr);
     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
@@ -406,9 +403,9 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
   }
 
   LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
-  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
+  ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src));
   LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
-  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
+  ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest));
   LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
 
   /* Now calculate and check the checksum */
@@ -443,8 +440,7 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
          IGMP_STATS_INC(igmp.rx_v1);
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
          igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
-       }
-       else {
+       } else {
          IGMP_STATS_INC(igmp.rx_general);
        }
 
@@ -462,9 +458,11 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
          ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
          if (ip_addr_cmp(dest, &allsystems)) {
+           ip_addr_t groupaddr;
            LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
-           /* we first need to re-lookfor the group since we used dest last time */
-           group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
+           /* we first need to re-look for the group since we used dest last time */
+           ip_addr_copy(groupaddr, igmp->igmp_group_address);
+           group = igmp_lookfor_group(inp, &groupaddr);
          } else {
            LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
          }
@@ -472,12 +470,10 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
          if (group != NULL) {
            IGMP_STATS_INC(igmp.rx_group);
            igmp_delaying_member(group, igmp->igmp_maxresp);
-         }
-         else {
+         } else {
            IGMP_STATS_INC(igmp.drop);
          }
-         }
-       else {
+       } else {
          IGMP_STATS_INC(igmp.proterr);
        }
      }
@@ -707,17 +703,6 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time)
   group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
 }
 
-/**
- * Stop a timer for an igmp_group
- *
- * @param group the igmp_group for which to stop the timer
- */
-static void
-igmp_stop_timer(struct igmp_group *group)
-{
-  group->timer = 0;
-}
-
 /**
  * Delaying membership report for a group if necessary
  *
@@ -783,7 +768,7 @@ igmp_send(struct igmp_group *group, u8_t type)
   p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
   
   if (p) {
-    igmp = p->payload;
+    igmp = (struct igmp_msg *)p->payload;
     LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
                (p->len >= sizeof(struct igmp_msg)));
     ip_addr_copy(src, group->netif->ip_addr);
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4.c
new file mode 100644 (file)
index 0000000..8cbaa23
--- /dev/null
@@ -0,0 +1,906 @@
+/**
+ * @file
+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
+ * 
+ * @see ip_frag.c
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/ip_frag.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp.h"
+#include "lwip/igmp.h"
+#include "lwip/raw.h"
+#include "lwip/udp.h"
+#include "lwip/tcp_impl.h"
+#include "lwip/snmp.h"
+#include "lwip/dhcp.h"
+#include "lwip/autoip.h"
+#include "lwip/stats.h"
+#include "arch/perf.h"
+
+#include <string.h>
+
+/** Set this to 0 in the rare case of wanting to call an extra function to
+ * generate the IP checksum (in contrast to calculating it on-the-fly). */
+#ifndef LWIP_INLINE_IP_CHKSUM
+#define LWIP_INLINE_IP_CHKSUM   1
+#endif
+#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
+#define CHECKSUM_GEN_IP_INLINE  1
+#else
+#define CHECKSUM_GEN_IP_INLINE  0
+#endif
+
+#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
+
+/** Some defines for DHCP to let link-layer-addressed packets through while the
+ * netif is down.
+ * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
+ * to return 1 if the port is accepted and 0 if the port is not accepted.
+ */
+#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
+/* accept DHCP client port and custom port */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
+         || (LWIP_IP_ACCEPT_UDP_PORT(port)))
+#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept custom port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))
+#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+/* accept DHCP client port only */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
+#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
+
+#else /* LWIP_DHCP */
+#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
+#endif /* LWIP_DHCP */
+
+/** Global data for both IPv4 and IPv6 */
+struct ip_globals ip_data;
+
+/** The IP header ID of the next outgoing IP packet */
+static u16_t ip_id;
+
+/**
+ * Finds the appropriate network interface for a given IP address. It
+ * searches the list of network interfaces linearly. A match is found
+ * if the masked IP address of the network interface equals the masked
+ * IP address given to the function.
+ *
+ * @param dest the destination IP address for which to find the route
+ * @return the netif on which to send to reach dest
+ */
+struct netif *
+ip_route(ip_addr_t *dest)
+{
+  struct netif *netif;
+
+#ifdef LWIP_HOOK_IP4_ROUTE
+  netif = LWIP_HOOK_IP4_ROUTE(dest);
+  if (netif != NULL) {
+    return netif;
+  }
+#endif
+
+  /* iterate through netifs */
+  for (netif = netif_list; netif != NULL; netif = netif->next) {
+    /* network mask matches? */
+    if (netif_is_up(netif)) {
+      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
+        /* return netif on which to forward IP packet */
+        return netif;
+      }
+    }
+  }
+  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    snmp_inc_ipoutnoroutes();
+    return NULL;
+  }
+  /* no matching netif found, use default netif */
+  return netif_default;
+}
+
+#if IP_FORWARD
+/**
+ * Determine whether an IP address is in a reserved set of addresses
+ * that may not be forwarded, or whether datagrams to that destination
+ * may be forwarded.
+ * @param p the packet to forward
+ * @param dest the destination IP address
+ * @return 1: can forward 0: discard
+ */
+static int
+ip_canforward(struct pbuf *p)
+{
+  u32_t addr = ip4_addr_get_u32(ip_current_dest_addr());
+
+  if (p->flags & PBUF_FLAG_LLBCAST) {
+    /* don't route link-layer broadcasts */
+    return 0;
+  }
+  if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) {
+    /* don't route link-layer multicasts unless the destination address is an IP
+       multicast address */
+    return 0;
+  }
+  if (IP_EXPERIMENTAL(addr)) {
+    return 0;
+  }
+  if (IP_CLASSA(addr)) {
+    u32_t net = addr & IP_CLASSA_NET;
+    if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) {
+      /* don't route loopback packets */
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/**
+ * Forwards an IP packet. It finds an appropriate route for the
+ * packet, decrements the TTL value of the packet, adjusts the
+ * checksum and outputs the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ */
+static void
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
+{
+  struct netif *netif;
+
+  PERF_START;
+
+  if (!ip_canforward(p)) {
+    goto return_noroute;
+  }
+
+  /* RFC3927 2.7: do not forward link-local addresses */
+  if (ip_addr_islinklocal(ip_current_dest_addr())) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
+      ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
+    goto return_noroute;
+  }
+
+  /* Find network interface where to forward this IP packet to. */
+  netif = ip_route(ip_current_dest_addr());
+  if (netif == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
+      ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
+      ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
+    goto return_noroute;
+  }
+#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF
+  /* Do not forward packets onto the same network interface on which
+   * they arrived. */
+  if (netif == inp) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
+    goto return_noroute;
+  }
+#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */
+
+  /* decrement TTL */
+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
+  /* send ICMP if TTL == 0 */
+  if (IPH_TTL(iphdr) == 0) {
+    snmp_inc_ipinhdrerrors();
+#if LWIP_ICMP
+    /* Don't send ICMP messages in response to ICMP messages */
+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
+      icmp_time_exceeded(p, ICMP_TE_TTL);
+    }
+#endif /* LWIP_ICMP */
+    return;
+  }
+
+  /* Incrementally update the IP checksum. */
+  if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
+  } else {
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
+  }
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+    ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
+    ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
+
+  IP_STATS_INC(ip.fw);
+  IP_STATS_INC(ip.xmit);
+  snmp_inc_ipforwdatagrams();
+
+  PERF_STOP("ip_forward");
+  /* transmit pbuf on chosen interface */
+  netif->output(netif, p, ip_current_dest_addr());
+  return;
+return_noroute:
+  snmp_inc_ipoutnoroutes();
+}
+#endif /* IP_FORWARD */
+
+/**
+ * This function is called by the network interface device driver when
+ * an IP packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip_forward). The IP checksum is always checked.
+ *
+ * Finally, the packet is sent to the upper layer protocol input function.
+ * 
+ * @param p the received IP packet (p->payload points to IP header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ *         processed, but currently always returns ERR_OK)
+ */
+err_t
+ip_input(struct pbuf *p, struct netif *inp)
+{
+  struct ip_hdr *iphdr;
+  struct netif *netif;
+  u16_t iphdr_hlen;
+  u16_t iphdr_len;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  IP_STATS_INC(ip.recv);
+  snmp_inc_ipinreceives();
+
+  /* identify the IP header */
+  iphdr = (struct ip_hdr *)p->payload;
+  if (IPH_V(iphdr) != 4) {
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.err);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+
+#ifdef LWIP_HOOK_IP4_INPUT
+  if (LWIP_HOOK_IP4_INPUT(p, inp)) {
+    /* the packet has been eaten */
+    return ERR_OK;
+  }
+#endif
+
+  /* obtain IP header length in number of 32-bit words */
+  iphdr_hlen = IPH_HL(iphdr);
+  /* calculate IP header length in bytes */
+  iphdr_hlen *= 4;
+  /* obtain ip length in bytes */
+  iphdr_len = ntohs(IPH_LEN(iphdr));
+
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
+    if (iphdr_hlen > p->len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_hlen, p->len));
+    }
+    if (iphdr_len > p->tot_len) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+        iphdr_len, p->tot_len));
+    }
+    /* free (drop) packet pbufs */
+    pbuf_free(p);
+    IP_STATS_INC(ip.lenerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipindiscards();
+    return ERR_OK;
+  }
+
+  /* verify checksum */
+#if CHECKSUM_CHECK_IP
+  if (inet_chksum(iphdr, iphdr_hlen) != 0) {
+
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
+    ip_debug_print(p);
+    pbuf_free(p);
+    IP_STATS_INC(ip.chkerr);
+    IP_STATS_INC(ip.drop);
+    snmp_inc_ipinhdrerrors();
+    return ERR_OK;
+  }
+#endif
+
+  /* Trim pbuf. This should have been done at the netif layer,
+   * but we'll do it anyway just to be sure that its done. */
+  pbuf_realloc(p, iphdr_len);
+
+  /* copy IP addresses to aligned ip_addr_t */
+  ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest);
+  ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src);
+
+  /* match packet against an interface, i.e. is this packet for us? */
+#if LWIP_IGMP
+  if (ip_addr_ismulticast(ip_current_dest_addr())) {
+    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) {
+      netif = inp;
+    } else {
+      netif = NULL;
+    }
+  } else
+#endif /* LWIP_IGMP */
+  {
+    /* start trying with inp. if that's not acceptable, start walking the
+       list of configured netifs.
+       'first' is used as a boolean to mark whether we started walking the list */
+    int first = 1;
+    netif = inp;
+    do {
+      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
+          ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
+          ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
+          ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
+
+      /* interface is up and configured? */
+      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
+        /* unicast to this interface address? */
+        if (ip_addr_cmp(ip_current_dest_addr(), &(netif->ip_addr)) ||
+            /* or broadcast on this interface network address? */
+            ip_addr_isbroadcast(ip_current_dest_addr(), netif)) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#if LWIP_AUTOIP
+        /* connections to link-local addresses must persist after changing
+           the netif's address (RFC3927 ch. 1.9) */
+        if ((netif->autoip != NULL) &&
+            ip_addr_cmp(ip_current_dest_addr(), &(netif->autoip->llipaddr))) {
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
+              netif->name[0], netif->name[1]));
+          /* break out of for loop */
+          break;
+        }
+#endif /* LWIP_AUTOIP */
+      }
+      if (first) {
+        first = 0;
+        netif = netif_list;
+      } else {
+        netif = netif->next;
+      }
+      if (netif == inp) {
+        netif = netif->next;
+      }
+    } while(netif != NULL);
+  }
+
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).
+   *
+   * If you want to accept private broadcast communication while a netif is down,
+   * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
+   *
+   * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
+   */
+  if (netif == NULL) {
+    /* remote port is DHCP server? */
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+      struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
+        ntohs(udphdr->dest)));
+      if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
+        netif = inp;
+        check_ip_src = 0;
+      }
+    }
+  }
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+
+  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
+  if (check_ip_src && !ip_addr_isany(ip_current_src_addr()))
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
+  {  if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) ||
+         (ip_addr_ismulticast(ip_current_src_addr()))) {
+      /* packet source is not valid */
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
+      /* free (drop) packet pbufs */
+      pbuf_free(p);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+      return ERR_OK;
+    }
+  }
+
+  /* packet not for us? */
+  if (netif == NULL) {
+    /* packet not for us, route or discard */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
+#if IP_FORWARD
+    /* non-broadcast packet? */
+    if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
+      /* try to forward IP packet on (other) interfaces */
+      ip_forward(p, iphdr, inp);
+    } else
+#endif /* IP_FORWARD */
+    {
+      snmp_inc_ipinaddrerrors();
+      snmp_inc_ipindiscards();
+    }
+    pbuf_free(p);
+    return ERR_OK;
+  }
+  /* packet consists of multiple fragments? */
+  if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */
+    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
+    /* reassemble the packet*/
+    p = ip_reass(p);
+    /* packet not fully reassembled yet? */
+    if (p == NULL) {
+      return ERR_OK;
+    }
+    iphdr = (struct ip_hdr *)p->payload;
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
+    pbuf_free(p);
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
+      ntohs(IPH_OFFSET(iphdr))));
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+#endif /* IP_REASSEMBLY */
+  }
+
+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
+
+#if LWIP_IGMP
+  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
+  if((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
+#else
+  if (iphdr_hlen > IP_HLEN) {
+#endif /* LWIP_IGMP */
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
+    pbuf_free(p);
+    IP_STATS_INC(ip.opterr);
+    IP_STATS_INC(ip.drop);
+    /* unsupported protocol feature */
+    snmp_inc_ipinunknownprotos();
+    return ERR_OK;
+  }
+#endif /* IP_OPTIONS_ALLOWED == 0 */
+
+  /* send to upper layers */
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
+  ip_debug_print(p);
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+  ip_data.current_netif = inp;
+  ip_data.current_ip4_header = iphdr;
+  ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4;
+
+#if LWIP_RAW
+  /* raw input did not eat the packet? */
+  if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+  {
+    pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
+
+    switch (IPH_PROTO(iphdr)) {
+#if LWIP_UDP
+    case IP_PROTO_UDP:
+#if LWIP_UDPLITE
+    case IP_PROTO_UDPLITE:
+#endif /* LWIP_UDPLITE */
+      snmp_inc_ipindelivers();
+      udp_input(p, inp);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+    case IP_PROTO_TCP:
+      snmp_inc_ipindelivers();
+      tcp_input(p, inp);
+      break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP
+    case IP_PROTO_ICMP:
+      snmp_inc_ipindelivers();
+      icmp_input(p, inp);
+      break;
+#endif /* LWIP_ICMP */
+#if LWIP_IGMP
+    case IP_PROTO_IGMP:
+      igmp_input(p, inp, ip_current_dest_addr());
+      break;
+#endif /* LWIP_IGMP */
+    default:
+#if LWIP_ICMP
+      /* send ICMP destination protocol unreachable unless is was a broadcast */
+      if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) &&
+          !ip_addr_ismulticast(ip_current_dest_addr())) {
+        pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */
+        p->payload = iphdr;
+        icmp_dest_unreach(p, ICMP_DUR_PROTO);
+      }
+#endif /* LWIP_ICMP */
+      pbuf_free(p);
+
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
+
+      IP_STATS_INC(ip.proterr);
+      IP_STATS_INC(ip.drop);
+      snmp_inc_ipinunknownprotos();
+    }
+  }
+
+  /* @todo: this is not really necessary... */
+  ip_data.current_netif = NULL;
+  ip_data.current_ip4_header = NULL;
+  ip_data.current_ip_header_tot_len = 0;
+  ip_addr_set_any(ip_current_src_addr());
+  ip_addr_set_any(ip_current_dest_addr());
+
+  return ERR_OK;
+}
+
+/**
+ * Sends an IP packet on a network interface. This function constructs
+ * the IP header and calculates the IP header checksum. If the source
+ * IP address is NULL, the IP address of the outgoing network
+ * interface is filled in as source address.
+ * If the destination IP address is IP_HDRINCL, p is assumed to already
+ * include an IP header and p->payload points to it instead of the data.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers
+ *         returns errors returned by netif->output
+ *
+ * @note ip_id: RFC791 "some host may be able to simply use
+ *  unique identifiers independent of destination"
+ */
+err_t
+ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+             u8_t ttl, u8_t tos,
+             u8_t proto, struct netif *netif)
+{
+#if IP_OPTIONS_SEND
+  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
+}
+
+/**
+ * Same as ip_output_if() but with the possibility to include IP options:
+ *
+ * @ param ip_options pointer to the IP options, copied into the IP header
+ * @ param optlen length of ip_options
+ */
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+       u16_t optlen)
+{
+#endif /* IP_OPTIONS_SEND */
+  struct ip_hdr *iphdr;
+  ip_addr_t dest_addr;
+#if CHECKSUM_GEN_IP_INLINE
+  u32_t chk_sum = 0;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  snmp_inc_ipoutrequests();
+
+  /* Should the IP header be generated or is it already included in p? */
+  if (dest != IP_HDRINCL) {
+    u16_t ip_hlen = IP_HLEN;
+#if IP_OPTIONS_SEND
+    u16_t optlen_aligned = 0;
+    if (optlen != 0) {
+#if CHECKSUM_GEN_IP_INLINE
+      int i;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+      /* round up to a multiple of 4 */
+      optlen_aligned = ((optlen + 3) & ~3);
+      ip_hlen += optlen_aligned;
+      /* First write in the IP options */
+      if (pbuf_header(p, optlen_aligned)) {
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
+        IP_STATS_INC(ip.err);
+        snmp_inc_ipoutdiscards();
+        return ERR_BUF;
+      }
+      MEMCPY(p->payload, ip_options, optlen);
+      if (optlen < optlen_aligned) {
+        /* zero the remaining bytes */
+        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
+      }
+#if CHECKSUM_GEN_IP_INLINE
+      for (i = 0; i < optlen_aligned/2; i++) {
+        chk_sum += ((u16_t*)p->payload)[i];
+      }
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    }
+#endif /* IP_OPTIONS_SEND */
+    /* generate IP header */
+    if (pbuf_header(p, IP_HLEN)) {
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
+
+      IP_STATS_INC(ip.err);
+      snmp_inc_ipoutdiscards();
+      return ERR_BUF;
+    }
+
+    iphdr = (struct ip_hdr *)p->payload;
+    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
+               (p->len >= sizeof(struct ip_hdr)));
+
+    IPH_TTL_SET(iphdr, ttl);
+    IPH_PROTO_SET(iphdr, proto);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += LWIP_MAKE_U16(proto, ttl);
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    /* dest cannot be NULL here */
+    ip_addr_copy(iphdr->dest, *dest);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+
+    IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
+    IPH_TOS_SET(iphdr, tos);
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_LEN_SET(iphdr, htons(p->tot_len));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_len;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    IPH_OFFSET_SET(iphdr, 0);
+    IPH_ID_SET(iphdr, htons(ip_id));
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += iphdr->_id;
+#endif /* CHECKSUM_GEN_IP_INLINE */
+    ++ip_id;
+
+    if (ip_addr_isany(src)) {
+      ip_addr_copy(iphdr->src, netif->ip_addr);
+    } else {
+      /* src cannot be NULL here */
+      ip_addr_copy(iphdr->src, *src);
+    }
+
+#if CHECKSUM_GEN_IP_INLINE
+    chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
+    chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
+    chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
+    chk_sum = (chk_sum >> 16) + chk_sum;
+    chk_sum = ~chk_sum;
+    iphdr->_chksum = chk_sum; /* network order */
+#else /* CHECKSUM_GEN_IP_INLINE */
+    IPH_CHKSUM_SET(iphdr, 0);
+#if CHECKSUM_GEN_IP
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
+#endif
+#endif /* CHECKSUM_GEN_IP_INLINE */
+  } else {
+    /* IP header already included in p */
+    iphdr = (struct ip_hdr *)p->payload;
+    ip_addr_copy(dest_addr, iphdr->dest);
+    dest = &dest_addr;
+  }
+
+  IP_STATS_INC(ip.xmit);
+
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+  ip_debug_print(p);
+
+#if ENABLE_LOOPBACK
+  if (ip_addr_cmp(dest, &netif->ip_addr)) {
+    /* Packet to self, enqueue it for loopback */
+    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
+    return netif_loop_output(netif, p, dest);
+  }
+#if LWIP_IGMP
+  if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
+    netif_loop_output(netif, p, dest);
+  }
+#endif /* LWIP_IGMP */
+#endif /* ENABLE_LOOPBACK */
+#if IP_FRAG
+  /* don't fragment if interface has mtu set to 0 [loopif] */
+  if (netif->mtu && (p->tot_len > netif->mtu)) {
+    return ip_frag(p, netif, dest);
+  }
+#endif /* IP_FRAG */
+
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
+  return netif->output(netif, p, dest);
+}
+
+/**
+ * Simple interface to ip_output_if. It finds the outgoing network
+ * interface and calls upon ip_output_if to do the actual work.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto)
+{
+  struct netif *netif;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
+}
+
+#if LWIP_NETIF_HWADDRHINT
+/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ *  before calling ip_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an IP
+            header and p->payload points to that IP header)
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
+ *         IP  address of the netif used to send is used as source address)
+ * @param dest the destination IP address to send the packet to
+ * @param ttl the TTL value to be set in the IP header
+ * @param tos the TOS value to be set in the IP header
+ * @param proto the PROTOCOL to be set in the IP header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ *        calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
+err_t
+ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+{
+  struct netif *netif;
+  err_t err;
+
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip_route(dest)) == NULL) {
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
+      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
+    IP_STATS_INC(ip.rterr);
+    return ERR_RTE;
+  }
+
+  NETIF_SET_HWADDRHINT(netif, addr_hint);
+  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
+  NETIF_SET_HWADDRHINT(netif, NULL);
+
+  return err;
+}
+#endif /* LWIP_NETIF_HWADDRHINT*/
+
+#if IP_DEBUG
+/* Print an IP header by using LWIP_DEBUGF
+ * @param p an IP packet, p->payload pointing to the IP header
+ */
+void
+ip_debug_print(struct pbuf *p)
+{
+  struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+  u8_t *payload;
+
+  payload = (u8_t *)iphdr + IP_HLEN;
+
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
+                    IPH_V(iphdr),
+                    IPH_HL(iphdr),
+                    IPH_TOS(iphdr),
+                    ntohs(IPH_LEN(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
+                    ntohs(IPH_ID(iphdr)),
+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
+                    IPH_TTL(iphdr),
+                    IPH_PROTO(iphdr),
+                    ntohs(IPH_CHKSUM(iphdr))));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
+                    ip4_addr1_16(&iphdr->src),
+                    ip4_addr2_16(&iphdr->src),
+                    ip4_addr3_16(&iphdr->src),
+                    ip4_addr4_16(&iphdr->src)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
+                    ip4_addr1_16(&iphdr->dest),
+                    ip4_addr2_16(&iphdr->dest),
+                    ip4_addr3_16(&iphdr->dest),
+                    ip4_addr4_16(&iphdr->dest)));
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+}
+#endif /* IP_DEBUG */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4_addr.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv4/ip4_addr.c
new file mode 100644 (file)
index 0000000..8f633ff
--- /dev/null
@@ -0,0 +1,312 @@
+/**
+ * @file
+ * This is the IPv4 address tools implementation.
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "lwip/netif.h"
+
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
+const ip_addr_t ip_addr_any = { IPADDR_ANY };
+const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
+
+/**
+ * Determine if an address is a broadcast address on a network interface 
+ * 
+ * @param addr address to be checked
+ * @param netif the network interface against which the address is checked
+ * @return returns non-zero if the address is a broadcast address
+ */
+u8_t
+ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
+{
+  ip_addr_t ipaddr;
+  ip4_addr_set_u32(&ipaddr, addr);
+
+  /* all ones (broadcast) or all zeroes (old skool broadcast) */
+  if ((~addr == IPADDR_ANY) ||
+      (addr == IPADDR_ANY)) {
+    return 1;
+  /* no broadcast support on this network interface? */
+  } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
+    /* the given address cannot be a broadcast address
+     * nor can we check against any broadcast addresses */
+    return 0;
+  /* address matches network interface address exactly? => no broadcast */
+  } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
+    return 0;
+  /*  on the same (sub) network... */
+  } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
+         /* ...and host identifier bits are all ones? =>... */
+          && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
+           (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
+    /* => network broadcast address */
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/** Checks if a netmask is valid (starting with ones, then only zeros)
+ *
+ * @param netmask the IPv4 netmask to check (in network byte order!)
+ * @return 1 if the netmask is valid, 0 if it is not
+ */
+u8_t
+ip4_addr_netmask_valid(u32_t netmask)
+{
+  u32_t mask;
+  u32_t nm_hostorder = lwip_htonl(netmask);
+
+  /* first, check for the first zero */
+  for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) == 0) {
+      break;
+    }
+  }
+  /* then check that there is no one */
+  for (; mask != 0; mask >>= 1) {
+    if ((nm_hostorder & mask) != 0) {
+      /* there is a one after the first zero -> invalid */
+      return 0;
+    }
+  }
+  /* no one after the first zero -> valid */
+  return 1;
+}
+
+/* Here for now until needed in other places in lwIP */
+#ifndef isprint
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#endif
+
+/**
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @return ip address in network order
+ */
+u32_t
+ipaddr_addr(const char *cp)
+{
+  ip_addr_t val;
+
+  if (ipaddr_aton(cp, &val)) {
+    return ip4_addr_get_u32(&val);
+  }
+  return (IPADDR_NONE);
+}
+
+/**
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ *
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")
+ * @param addr pointer to which to save the ip address in network order
+ * @return 1 if cp could be converted to addr, 0 on failure
+ */
+int
+ipaddr_aton(const char *cp, ip_addr_t *addr)
+{
+  u32_t val;
+  u8_t base;
+  char c;
+  u32_t parts[4];
+  u32_t *pp = parts;
+
+  c = *cp;
+  for (;;) {
+    /*
+     * Collect number up to ``.''.
+     * Values are specified as for C:
+     * 0x=hex, 0=octal, 1-9=decimal.
+     */
+    if (!isdigit(c))
+      return (0);
+    val = 0;
+    base = 10;
+    if (c == '0') {
+      c = *++cp;
+      if (c == 'x' || c == 'X') {
+        base = 16;
+        c = *++cp;
+      } else
+        base = 8;
+    }
+    for (;;) {
+      if (isdigit(c)) {
+        val = (val * base) + (int)(c - '0');
+        c = *++cp;
+      } else if (base == 16 && isxdigit(c)) {
+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
+        c = *++cp;
+      } else
+        break;
+    }
+    if (c == '.') {
+      /*
+       * Internet format:
+       *  a.b.c.d
+       *  a.b.c   (with c treated as 16 bits)
+       *  a.b (with b treated as 24 bits)
+       */
+      if (pp >= parts + 3) {
+        return (0);
+      }
+      *pp++ = val;
+      c = *++cp;
+    } else
+      break;
+  }
+  /*
+   * Check for trailing characters.
+   */
+  if (c != '\0' && !isspace(c)) {
+    return (0);
+  }
+  /*
+   * Concoct the address according to
+   * the number of parts specified.
+   */
+  switch (pp - parts + 1) {
+
+  case 0:
+    return (0);       /* initial nondigit */
+
+  case 1:             /* a -- 32 bits */
+    break;
+
+  case 2:             /* a.b -- 8.24 bits */
+    if (val > 0xffffffUL) {
+      return (0);
+    }
+    val |= parts[0] << 24;
+    break;
+
+  case 3:             /* a.b.c -- 8.8.16 bits */
+    if (val > 0xffff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16);
+    break;
+
+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */
+    if (val > 0xff) {
+      return (0);
+    }
+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+    break;
+  default:
+    LWIP_ASSERT("unhandled", 0);
+    break;
+  }
+  if (addr) {
+    ip4_addr_set_u32(addr, htonl(val));
+  }
+  return (1);
+}
+
+/**
+ * Convert numeric IP address into decimal dotted ASCII representation.
+ * returns ptr to static buffer; not reentrant!
+ *
+ * @param addr ip address in network order to convert
+ * @return pointer to a global static (!) buffer that holds the ASCII
+ *         represenation of addr
+ */
+char *
+ipaddr_ntoa(const ip_addr_t *addr)
+{
+  static char str[16];
+  return ipaddr_ntoa_r(addr, str, 16);
+}
+
+/**
+ * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
+ *
+ * @param addr ip address in network order to convert
+ * @param buf target buffer where the string is stored
+ * @param buflen length of buf
+ * @return either pointer to buf which now holds the ASCII
+ *         representation of addr or NULL if buf was too small
+ */
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
+{
+  u32_t s_addr;
+  char inv[3];
+  char *rp;
+  u8_t *ap;
+  u8_t rem;
+  u8_t n;
+  u8_t i;
+  int len = 0;
+
+  s_addr = ip4_addr_get_u32(addr);
+
+  rp = buf;
+  ap = (u8_t *)&s_addr;
+  for(n = 0; n < 4; n++) {
+    i = 0;
+    do {
+      rem = *ap % (u8_t)10;
+      *ap /= (u8_t)10;
+      inv[i++] = '0' + rem;
+    } while(*ap);
+    while(i--) {
+      if (len++ >= buflen) {
+        return NULL;
+      }
+      *rp++ = inv[i];
+    }
+    if (len++ >= buflen) {
+      return NULL;
+    }
+    *rp++ = '.';
+    ap++;
+  }
+  *--rp = 0;
+  return buf;
+}
index f2af84b2a99b8152341d77eaf07ea6ed55ffe57a..8d184345dff0809a51a6acdc7dffca03d8bc2ea0 100644 (file)
@@ -197,7 +197,7 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
     clen = pbuf_clen(pcur);
     LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
     pbufs_freed += clen;
-    pbuf_free(pcur);    
+    pbuf_free(pcur);
   }
   /* Then, unchain the struct ip_reassdata from the list and free it. */
   ip_reass_dequeue_datagram(ipr, prev);
@@ -616,6 +616,38 @@ nullreturn:
 #if IP_FRAG
 #if IP_FRAG_USES_STATIC_BUF
 static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
+#else /* IP_FRAG_USES_STATIC_BUF */
+
+#if !LWIP_NETIF_TX_SINGLE_PBUF
+/** Allocate a new struct pbuf_custom_ref */
+static struct pbuf_custom_ref*
+ip_frag_alloc_pbuf_custom_ref(void)
+{
+  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
+}
+
+/** Free a struct pbuf_custom_ref */
+static void
+ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
+{
+  LWIP_ASSERT("p != NULL", p != NULL);
+  memp_free(MEMP_FRAG_PBUF, p);
+}
+
+/** Free-callback function to free a 'struct pbuf_custom_ref', called by
+ * pbuf_free. */
+static void
+ipfrag_free_pbuf_custom(struct pbuf *p)
+{
+  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
+  LWIP_ASSERT("pcr != NULL", pcr != NULL);
+  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
+  if (pcr->original != NULL) {
+    pbuf_free(pcr->original);
+  }
+  ip_frag_free_pbuf_custom_ref(pcr);
+}
+#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
 #endif /* IP_FRAG_USES_STATIC_BUF */
 
 /**
@@ -674,7 +706,7 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
   iphdr = (struct ip_hdr *)rambuf->payload;
   SMEMCPY(iphdr, p->payload, IP_HLEN);
 #else /* IP_FRAG_USES_STATIC_BUF */
-  original_iphdr = p->payload;
+  original_iphdr = (struct ip_hdr *)p->payload;
   iphdr = original_iphdr;
 #endif /* IP_FRAG_USES_STATIC_BUF */
 
@@ -731,7 +763,7 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
     LWIP_ASSERT("this needs a pbuf in one piece!",
                 (p->len >= (IP_HLEN)));
     SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
-    iphdr = rambuf->payload;
+    iphdr = (struct ip_hdr *)rambuf->payload;
 
     /* Can just adjust p directly for needed offset. */
     p->payload = (u8_t *)p->payload + poff;
@@ -739,20 +771,29 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
 
     left_to_copy = cop;
     while (left_to_copy) {
+      struct pbuf_custom_ref *pcr;
       newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
       /* Is this pbuf already empty? */
       if (!newpbuflen) {
         p = p->next;
         continue;
       }
-      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
-      if (newpbuf == NULL) {
+      pcr = ip_frag_alloc_pbuf_custom_ref();
+      if (pcr == NULL) {
         pbuf_free(rambuf);
         return ERR_MEM;
       }
       /* Mirror this pbuf, although we might not need all of it. */
-      newpbuf->payload = p->payload;
-      newpbuf->len = newpbuf->tot_len = newpbuflen;
+      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
+      if (newpbuf == NULL) {
+        ip_frag_free_pbuf_custom_ref(pcr);
+        pbuf_free(rambuf);
+        return ERR_MEM;
+      }
+      pbuf_ref(p);
+      pcr->original = p;
+      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
+
       /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
        * so that it is removed when pbuf_dechain is later called on rambuf.
        */
@@ -760,7 +801,7 @@ ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
       left_to_copy -= newpbuflen;
       if (left_to_copy) {
         p = p->next;
-    }
+      }
     }
     poff = newpbuflen;
 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/dhcp6.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/dhcp6.c
new file mode 100644 (file)
index 0000000..9656c3b
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * @file
+ *
+ * DHCPv6.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/ip6_addr.h"
+#include "lwip/def.h"
+
+
+#endif /* LWIP_IPV6_DHCP6 */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ethip6.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ethip6.c
new file mode 100644 (file)
index 0000000..9941010
--- /dev/null
@@ -0,0 +1,195 @@
+/**
+ * @file
+ *
+ * Ethernet output for IPv6. Uses ND tables for link-layer addressing.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6 && LWIP_ETHERNET
+
+#include "lwip/ethip6.h"
+#include "lwip/nd6.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp6.h"
+
+#include <string.h>
+
+#define ETHTYPE_IPV6        0x86DD
+
+/** The ethernet address */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_addr {
+  PACK_STRUCT_FIELD(u8_t addr[6]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Ethernet header */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct eth_hdr {
+#if ETH_PAD_SIZE
+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
+#endif
+  PACK_STRUCT_FIELD(struct eth_addr dest);
+  PACK_STRUCT_FIELD(struct eth_addr src);
+  PACK_STRUCT_FIELD(u16_t type);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
+
+/**
+ * Send an IPv6 packet on the network using netif->linkoutput
+ * The ethernet header is filled in before sending.
+ *
+ * @params netif the lwIP network interface on which to send the packet
+ * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
+ * @params src the source MAC address to be copied into the ethernet header
+ * @params dst the destination MAC address to be copied into the ethernet header
+ * @return ERR_OK if the packet was sent, any other err_t on failure
+ */
+static err_t
+ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
+{
+  struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
+
+  LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!",
+              (netif->hwaddr_len == 6));
+  SMEMCPY(&ethhdr->dest, dst, 6);
+  SMEMCPY(&ethhdr->src, src, 6);
+  ethhdr->type = PP_HTONS(ETHTYPE_IPV6);
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p));
+  /* send the packet */
+  return netif->linkoutput(netif, p);
+}
+
+/**
+ * Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
+ *
+ * For IPv6 multicast, corresponding Ethernet addresses
+ * are selected and the packet is transmitted on the link.
+ *
+ * For unicast addresses, ...
+ *
+ * @TODO anycast addresses
+ *
+ * @param netif The lwIP network interface which the IP packet will be sent on.
+ * @param q The pbuf(s) containing the IP packet to be sent.
+ * @param ip6addr The IP address of the packet destination.
+ *
+ * @return
+ * - ERR_RTE No route to destination (no gateway to external networks),
+ * or the return type of either etharp_query() or etharp_send_ip().
+ */
+err_t
+ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
+{
+  struct eth_addr dest;
+  s8_t i;
+
+  /* make room for Ethernet header - should not fail */
+  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
+    /* bail out */
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
+      ("etharp_output: could not allocate room for header.\n"));
+    return ERR_BUF;
+  }
+
+  /* multicast destination IP address? */
+  if (ip6_addr_ismulticast(ip6addr)) {
+    /* Hash IP multicast address to MAC address.*/
+    dest.addr[0] = 0x33;
+    dest.addr[1] = 0x33;
+    dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0];
+    dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1];
+    dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2];
+    dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3];
+
+    /* Send out. */
+    return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
+  }
+
+  /* We have a unicast destination IP address */
+  /* TODO anycast? */
+  /* Get next hop record. */
+  i = nd6_get_next_hop_entry(ip6addr, netif);
+  if (i < 0) {
+    /* failed to get a next hop neighbor record. */
+    return ERR_MEM;
+  }
+
+  /* Now that we have a destination record, send or queue the packet. */
+  if (neighbor_cache[i].state == ND6_STALE) {
+    /* Switch to delay state. */
+    neighbor_cache[i].state = ND6_DELAY;
+    neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
+  }
+  /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */
+  if ((neighbor_cache[i].state == ND6_REACHABLE) ||
+      (neighbor_cache[i].state == ND6_DELAY) ||
+      (neighbor_cache[i].state == ND6_PROBE)) {
+
+    /* Send out. */
+    SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
+    return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
+  }
+
+  /* We should queue packet on this interface. */
+  pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
+  nd6_queue_packet(i, q);
+
+  return ERR_OK;
+}
+
+#endif /* LWIP_IPV6 && LWIP_ETHERNET */
index 4fcc8955110981f1209d5b03a078c56f24b18413..be725c2ddf1192fee00bd1fcfe18aa3f659fb1f0 100644 (file)
@@ -1,5 +1,11 @@
+/**
+ * @file
+ *
+ * IPv6 version of ICMP, as per RFC 4443.
+ */
+
 /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * Copyright (c) 2010 Inico Technologies Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification,
  *
  * This file is part of the lwIP TCP/IP stack.
  *
- * Author: Adam Dunkels <adam@sics.se>
+ * Author: Ivan Delamer <delamer@inicotech.com>
  *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
  */
 
-/* Some ICMP messages should be passed to the transport protocols. This
-   is not implemented. */
-
 #include "lwip/opt.h"
 
-#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
+#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
 
-#include "lwip/icmp.h"
-#include "lwip/inet.h"
-#include "lwip/ip.h"
-#include "lwip/def.h"
+#include "lwip/icmp6.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/nd6.h"
+#include "lwip/mld6.h"
 #include "lwip/stats.h"
 
+#include <string.h>
+
+#ifndef LWIP_ICMP6_DATASIZE
+#define LWIP_ICMP6_DATASIZE   8
+#endif
+#if LWIP_ICMP6_DATASIZE == 0
+#define LWIP_ICMP6_DATASIZE   8
+#endif
+
+/* Forward declarations */
+static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
+
+
+/**
+ * Process an input ICMPv6 message. Called by ip6_input.
+ *
+ * Will generate a reply for echo requests. Other messages are forwarded
+ * to nd6_input, or mld6_input.
+ *
+ * @param p the mld packet, p->payload pointing to the icmpv6 header
+ * @param inp the netif on which this packet was received
+ */
 void
-icmp_input(struct pbuf *p, struct netif *inp)
+icmp6_input(struct pbuf *p, struct netif *inp)
 {
-  u8_t type;
-  struct icmp_echo_hdr *iecho;
-  struct ip_hdr *iphdr;
-  struct ip_addr tmpaddr;
+  struct icmp6_hdr *icmp6hdr;
+  struct pbuf * r;
+  ip6_addr_t * reply_src;
 
-  ICMP_STATS_INC(icmp.recv);
+  ICMP6_STATS_INC(icmp6.recv);
 
-  /* TODO: check length before accessing payload! */
+  /* Check that ICMPv6 header fits in payload */
+  if (p->len < sizeof(struct icmp6_hdr)) {
+    /* drop short packets */
+    pbuf_free(p);
+    ICMP6_STATS_INC(icmp6.lenerr);
+    ICMP6_STATS_INC(icmp6.drop);
+    return;
+  }
 
-  type = ((u8_t *)p->payload)[0];
+  icmp6hdr = (struct icmp6_hdr *)p->payload;
 
-  switch (type) {
-  case ICMP6_ECHO:
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
+#if LWIP_ICMP6_CHECKSUM_CHECK
+  if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
+                        ip6_current_dest_addr()) != 0) {
+    /* Checksum failed */
+    pbuf_free(p);
+    ICMP6_STATS_INC(icmp6.chkerr);
+    ICMP6_STATS_INC(icmp6.drop);
+    return;
+  }
+#endif /* LWIP_ICMP6_CHECKSUM_CHECK */
 
-    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
-      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
+  switch (icmp6hdr->type) {
+  case ICMP6_TYPE_NA: /* Neighbor advertisement */
+  case ICMP6_TYPE_NS: /* Neighbor solicitation */
+  case ICMP6_TYPE_RA: /* Router advertisement */
+  case ICMP6_TYPE_RD: /* Redirect */
+  case ICMP6_TYPE_PTB: /* Packet too big */
+    nd6_input(p, inp);
+    return;
+    break;
+  case ICMP6_TYPE_RS:
+#if LWIP_IPV6_FORWARD
+    /* TODO implement router functionality */
+#endif
+    break;
+#if LWIP_IPV6_MLD
+  case ICMP6_TYPE_MLQ:
+  case ICMP6_TYPE_MLR:
+  case ICMP6_TYPE_MLD:
+    mld6_input(p, inp);
+    return;
+    break;
+#endif
+  case ICMP6_TYPE_EREQ:
+#if !LWIP_MULTICAST_PING
+    /* multicast destination address? */
+    if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
+      /* drop */
+      pbuf_free(p);
+      ICMP6_STATS_INC(icmp6.drop);
+      return;
+    }
+#endif /* LWIP_MULTICAST_PING */
 
+    /* Allocate reply. */
+    r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
+    if (r == NULL) {
+      /* drop */
       pbuf_free(p);
-      ICMP_STATS_INC(icmp.lenerr);
+      ICMP6_STATS_INC(icmp6.memerr);
       return;
     }
-    iecho = p->payload;
-    iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
-    if (inet_chksum_pbuf(p) != 0) {
-      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
-      ICMP_STATS_INC(icmp.chkerr);
-    /*      return;*/
+
+    /* Copy echo request. */
+    if (pbuf_copy(r, p) != ERR_OK) {
+      /* drop */
+      pbuf_free(p);
+      pbuf_free(r);
+      ICMP6_STATS_INC(icmp6.err);
+      return;
     }
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
-    ip_addr_set(&tmpaddr, &(iphdr->src));
-    ip_addr_set(&(iphdr->src), &(iphdr->dest));
-    ip_addr_set(&(iphdr->dest), &tmpaddr);
-    iecho->type = ICMP6_ER;
-    /* adjust the checksum */
-    if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
-      iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
-    } else {
-      iecho->chksum += htons(ICMP6_ECHO << 8);
+
+    /* Determine reply source IPv6 address. */
+    reply_src = ip6_select_source_address(inp, ip6_current_src_addr());
+    if (reply_src == NULL) {
+      /* drop */
+      pbuf_free(p);
+      pbuf_free(r);
+      ICMP6_STATS_INC(icmp6.rterr);
+      return;
     }
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
-    ICMP_STATS_INC(icmp.xmit);
 
-    /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
-    ip_output_if (p, &(iphdr->src), IP_HDRINCL,
-     iphdr->hoplim, IP_PROTO_ICMP, inp);
+    /* Set fields in reply. */
+    ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
+    ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
+    ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
+        IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
+
+    /* Send reply. */
+    ICMP6_STATS_INC(icmp6.xmit);
+    ip6_output_if(r, reply_src, ip6_current_src_addr(),
+        LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
+    pbuf_free(r);
+
     break;
   default:
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
-    ICMP_STATS_INC(icmp.proterr);
-    ICMP_STATS_INC(icmp.drop);
+    ICMP6_STATS_INC(icmp6.proterr);
+    ICMP6_STATS_INC(icmp6.drop);
+    break;
   }
 
   pbuf_free(p);
 }
 
+
+/**
+ * Send an icmpv6 'destination unreachable' packet.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IPv6 header
+ * @param c ICMPv6 code for the unreachable type
+ */
 void
-icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
+icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
 {
-  struct pbuf *q;
-  struct ip_hdr *iphdr;
-  struct icmp_dur_hdr *idur;
-
-  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
-  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
-  /* ICMP header + IP header + 8 bytes of data */
-  if (q == NULL) {
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
-    pbuf_free(p);
-    return;
-  }
-  LWIP_ASSERT("check that first pbuf can hold icmp message",
-             (q->len >= (8 + IP_HLEN + 8)));
-
-  iphdr = p->payload;
-
-  idur = q->payload;
-  idur->type = (u8_t)ICMP6_DUR;
-  idur->icode = (u8_t)t;
-
-  SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
+  icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
+}
 
-  /* calculate checksum */
-  idur->chksum = 0;
-  idur->chksum = inet_chksum(idur, q->len);
-  ICMP_STATS_INC(icmp.xmit);
+/**
+ * Send an icmpv6 'packet too big' packet.
+ *
+ * @param p the input packet for which the 'packet too big' should be sent,
+ *          p->payload pointing to the IPv6 header
+ * @param mtu the maximum mtu that we can accept
+ */
+void
+icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
+{
+  icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
+}
 
-  ip_output(q, NULL,
-      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
-  pbuf_free(q);
+/**
+ * Send an icmpv6 'time exceeded' packet.
+ *
+ * @param p the input packet for which the 'unreachable' should be sent,
+ *          p->payload pointing to the IPv6 header
+ * @param c ICMPv6 code for the time exceeded type
+ */
+void
+icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
+{
+  icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
 }
 
+/**
+ * Send an icmpv6 'parameter problem' packet.
+ *
+ * @param p the input packet for which the 'param problem' should be sent,
+ *          p->payload pointing to the IP header
+ * @param c ICMPv6 code for the param problem type
+ * @param pointer the pointer to the byte where the parameter is found
+ */
 void
-icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
+icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
 {
-  struct pbuf *q;
-  struct ip_hdr *iphdr;
-  struct icmp_te_hdr *tehdr;
+  icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
+}
 
-  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
+/**
+ * Send an ICMPv6 packet in response to an incoming packet.
+ *
+ * @param p the input packet for which the response should be sent,
+ *          p->payload pointing to the IPv6 header
+ * @param code Code of the ICMPv6 header
+ * @param data Additional 32-bit parameter in the ICMPv6 header
+ * @param type Type of the ICMPv6 header
+ */
+static void
+icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
+{
+  struct pbuf *q;
+  struct icmp6_hdr *icmp6hdr;
+  ip6_addr_t * reply_src;
 
-  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
-  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
-  /* ICMP header + IP header + 8 bytes of data */
+  /* ICMPv6 header + IPv6 header + data */
+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
+                 PBUF_RAM);
   if (q == NULL) {
-    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
-    pbuf_free(p);
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
+    ICMP6_STATS_INC(icmp6.memerr);
     return;
   }
-  LWIP_ASSERT("check that first pbuf can hold icmp message",
-             (q->len >= (8 + IP_HLEN + 8)));
-
-  iphdr = p->payload;
+  LWIP_ASSERT("check that first pbuf can hold icmp 6message",
+             (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
 
-  tehdr = q->payload;
-  tehdr->type = (u8_t)ICMP6_TE;
-  tehdr->icode = (u8_t)t;
+  icmp6hdr = (struct icmp6_hdr *)q->payload;
+  icmp6hdr->type = type;
+  icmp6hdr->code = code;
+  icmp6hdr->data = data;
 
   /* copy fields from original packet */
-  SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
+          IP6_HLEN + LWIP_ICMP6_DATASIZE);
+
+  /* Select an address to use as source. */
+  reply_src = ip6_select_source_address(ip_current_netif(), ip6_current_src_addr());
+  if (reply_src == NULL) {
+    /* drop */
+    pbuf_free(q);
+    ICMP6_STATS_INC(icmp6.rterr);
+    return;
+  }
 
   /* calculate checksum */
-  tehdr->chksum = 0;
-  tehdr->chksum = inet_chksum(tehdr, q->len);
-  ICMP_STATS_INC(icmp.xmit);
-  ip_output(q, NULL,
-      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
+  icmp6hdr->chksum = 0;
+  icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
+    reply_src, ip6_current_src_addr());
+
+  ICMP6_STATS_INC(icmp6.xmit);
+  ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6);
   pbuf_free(q);
 }
 
-#endif /* LWIP_ICMP */
+#endif /* LWIP_ICMP6 && LWIP_IPV6 */
index c3de85c0930211de5b970995b723008f18b5ae43..bdf4ff4ffe361158253cb75b0f3afd3891d0a769 100644 (file)
@@ -1,12 +1,11 @@
 /**
  * @file
- * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
- * byte order functions.
  *
+ * INET v6 addresses.
  */
 
 /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * Copyright (c) 2010 Inico Technologies Ltd.
  * All rights reserved. 
  * 
  * Redistribution and use in source and binary forms, with or without modification, 
  *
  * This file is part of the lwIP TCP/IP stack.
  * 
- * Author: Adam Dunkels <adam@sics.se>
+ * Author: Ivan Delamer <delamer@inicotech.com>
  *
- */
-
-#include "lwip/opt.h"
-
-#include "lwip/def.h"
-#include "lwip/inet.h"
-
-/* chksum:
  *
- * Sums up all 16 bit words in a memory portion. Also includes any odd byte.
- * This function is used by the other checksum functions.
- *
- * For now, this is not optimized. Must be optimized for the particular processor
- * arcitecture on which it is to run. Preferebly coded in assembler.
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
  */
 
-static u32_t
-chksum(void *dataptr, u16_t len)
-{
-  u16_t *sdataptr = dataptr;
-  u32_t acc;
-  
-  
-  for(acc = 0; len > 1; len -= 2) {
-    acc += *sdataptr++;
-  }
-
-  /* add up any odd byte */
-  if (len == 1) {
-    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
-  }
-
-  return acc;
-
-}
-
-/* inet_chksum_pseudo:
- *
- * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
- */
-
-u16_t
-inet_chksum_pseudo(struct pbuf *p,
-       struct ip_addr *src, struct ip_addr *dest,
-       u8_t proto, u32_t proto_len)
-{
-  u32_t acc;
-  struct pbuf *q;
-  u8_t swapped, i;
-
-  acc = 0;
-  swapped = 0;
-  for(q = p; q != NULL; q = q->next) {    
-    acc += chksum(q->payload, q->len);
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-    }
-  }
-
-  if (swapped) {
-    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-  }
-  
-  for(i = 0; i < 8; i++) {
-    acc += ((u16_t *)src->addr)[i] & 0xffff;
-    acc += ((u16_t *)dest->addr)[i] & 0xffff;
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }
-  }
-  acc += (u16_t)htons((u16_t)proto);
-  acc += ((u16_t *)&proto_len)[0] & 0xffff;
-  acc += ((u16_t *)&proto_len)[1] & 0xffff;
+#include "lwip/opt.h"
 
-  while (acc >> 16) {
-    acc = (acc & 0xffff) + (acc >> 16);
-  }
-  return ~(acc & 0xffff);
-}
+#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
 
-/* inet_chksum:
- *
- * Calculates the Internet checksum over a portion of memory. Used primarely for IP
- * and ICMP.
- */
-
-u16_t
-inet_chksum(void *dataptr, u16_t len)
-{
-  u32_t acc, sum;
+#include "lwip/def.h"
+#include "lwip/inet6.h"
 
-  acc = chksum(dataptr, len);
-  sum = (acc & 0xffff) + (acc >> 16);
-  sum += (sum >> 16);
-  return ~(sum & 0xffff);
-}
+/** @see ip6_addr.c for implementation of functions. */
 
-u16_t
-inet_chksum_pbuf(struct pbuf *p)
-{
-  u32_t acc;
-  struct pbuf *q;
-  u8_t swapped;
-  
-  acc = 0;
-  swapped = 0;
-  for(q = p; q != NULL; q = q->next) {
-    acc += chksum(q->payload, q->len);
-    while (acc >> 16) {
-      acc = (acc & 0xffff) + (acc >> 16);
-    }    
-    if (q->len % 2 != 0) {
-      swapped = 1 - swapped;
-      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
-    }
-  }
-  if (swapped) {
-    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
-  }
-  return ~(acc & 0xffff);
-}
+#endif /* LWIP_IPV6 */
index b945fc5d35d814fbc94a9800af89235541ec416a..bae27ecead151349bcd667beb9d41c1ecce12793 100644 (file)
@@ -1,5 +1,11 @@
+/**
+ * @file
+ *
+ * IPv6 layer.
+ */
+
 /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * Copyright (c) 2010 Inico Technologies Ltd.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification,
  *
  * This file is part of the lwIP TCP/IP stack.
  *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
-
-
-
-/* ip.c
+ * Author: Ivan Delamer <delamer@inicotech.com>
  *
- * This is the code for the IP layer for IPv6.
  *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
  */
 
 
 #include "lwip/opt.h"
 
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
 #include "lwip/def.h"
 #include "lwip/mem.h"
-#include "lwip/ip.h"
-#include "lwip/inet.h"
 #include "lwip/netif.h"
-#include "lwip/icmp.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/ip6_frag.h"
+#include "lwip/icmp6.h"
+#include "lwip/raw.h"
 #include "lwip/udp.h"
 #include "lwip/tcp_impl.h"
-
+#include "lwip/dhcp6.h"
+#include "lwip/nd6.h"
+#include "lwip/mld6.h"
+#include "lwip/debug.h"
 #include "lwip/stats.h"
 
-#include "arch/perf.h"
 
-/* ip_init:
+/**
+ * Finds the appropriate network interface for a given IPv6 address. It tries to select
+ * a netif following a sequence of heuristics:
+ * 1) if there is only 1 netif, return it
+ * 2) if the destination is a link-local address, try to match the src address to a netif.
+ *    this is a tricky case because with multiple netifs, link-local addresses only have
+ *    meaning within a particular subnet/link.
+ * 3) tries to match the destination subnet to a configured address
+ * 4) tries to find a router
+ * 5) tries to match the source address to the netif
+ * 6) returns the default netif, if configured
  *
- * Initializes the IP layer.
+ * @param src the source IPv6 address, if known
+ * @param dest the destination IPv6 address for which to find the route
+ * @return the netif on which to send to reach dest
  */
-
-void
-ip_init(void)
-{
-}
-
-/* ip_route:
- *
- * Finds the appropriate network interface for a given IP address. It searches the
- * list of network interfaces linearly. A match is found if the masked IP address of
- * the network interface equals the masked IP address given to the function.
- */
-
 struct netif *
-ip_route(struct ip_addr *dest)
+ip6_route(struct ip6_addr *src, struct ip6_addr *dest)
 {
   struct netif *netif;
+  s8_t i;
+
+  /* If single netif configuration, fast return. */
+  if ((netif_list != NULL) && (netif_list->next == NULL)) {
+    return netif_list;
+  }
 
+  /* Special processing for link-local addresses. */
+  if (ip6_addr_islinklocal(dest)) {
+    if (ip6_addr_isany(src)) {
+      /* Use default netif. */
+      return netif_default;
+    }
+
+    /* Try to find the netif for the source address. */
+    for(netif = netif_list; netif != NULL; netif = netif->next) {
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+            ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
+          return netif;
+        }
+      }
+    }
+
+    /* netif not found, use default netif */
+    return netif_default;
+  }
+
+  /* See if the destination subnet matches a configured address. */
   for(netif = netif_list; netif != NULL; netif = netif->next) {
-    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
-      return netif;
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+      if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+          ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+        return netif;
+      }
     }
   }
 
+  /* Get the netif for a suitable router. */
+  i = nd6_select_router(dest, NULL);
+  if (i >= 0) {
+    if (default_router_list[i].neighbor_entry != NULL) {
+      if (default_router_list[i].neighbor_entry->netif != NULL) {
+        return default_router_list[i].neighbor_entry->netif;
+      }
+    }
+  }
+
+  /* try with the netif that matches the source address. */
+  if (!ip6_addr_isany(src)) {
+    for(netif = netif_list; netif != NULL; netif = netif->next) {
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+            ip6_addr_cmp(src, netif_ip6_addr(netif, i))) {
+          return netif;
+        }
+      }
+    }
+  }
+
+  /* no matching netif found, use default netif */
   return netif_default;
 }
 
-/* ip_forward:
+/**
+ * Select the best IPv6 source address for a given destination
+ * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior
+ * is assumed.
  *
- * Forwards an IP packet. It finds an appropriate route for the packet, decrements
- * the TTL value of the packet, adjusts the checksum and outputs the packet on the
- * appropriate interface.
+ * @param netif the netif on which to send a packet
+ * @param dest the destination we are trying to reach
+ * @return the most suitable source address to use, or NULL if no suitable
+ *         source address is found
  */
+ip6_addr_t *
+ip6_select_source_address(struct netif *netif, ip6_addr_t * dest)
+{
+  ip6_addr_t * src = NULL;
+  u8_t i;
+
+  /* If dest is link-local, choose a link-local source. */
+  if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) {
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+      if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+          ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
+        return netif_ip6_addr(netif, i);
+      }
+    }
+  }
+
+  /* Choose a site-local with matching prefix. */
+  if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) {
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+      if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+          ip6_addr_issitelocal(netif_ip6_addr(netif, i)) &&
+          ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+        return netif_ip6_addr(netif, i);
+      }
+    }
+  }
+
+  /* Choose a unique-local with matching prefix. */
+  if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) {
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+      if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+          ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) &&
+          ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+        return netif_ip6_addr(netif, i);
+      }
+    }
+  }
+
+  /* Choose a global with best matching prefix. */
+  if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) {
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+      if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+          ip6_addr_isglobal(netif_ip6_addr(netif, i))) {
+        if (src == NULL) {
+          src = netif_ip6_addr(netif, i);
+        }
+        else {
+          /* Replace src only if we find a prefix match. */
+          /* TODO find longest matching prefix. */
+          if ((!(ip6_addr_netcmp(src, dest))) &&
+              ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) {
+            src = netif_ip6_addr(netif, i);
+          }
+        }
+      }
+    }
+    if (src != NULL) {
+      return src;
+    }
+  }
+
+  /* Last resort: see if arbitrary prefix matches. */
+  for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+    if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+        ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
+      return netif_ip6_addr(netif, i);
+    }
+  }
+
+  return NULL;
+}
 
+#if LWIP_IPV6_FORWARD
+/**
+ * Forwards an IPv6 packet. It finds an appropriate route for the
+ * packet, decrements the HL value of the packet, and outputs
+ * the packet on the appropriate interface.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IPv6 header of the input packet
+ * @param inp the netif on which this packet was received
+ */
 static void
-ip_forward(struct pbuf *p, struct ip_hdr *iphdr)
+ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
 {
   struct netif *netif;
 
-  PERF_START;
-
-  if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {
-
-    LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));
-#if IP_DEBUG
-    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-#endif /* IP_DEBUG */
-    LWIP_DEBUGF(IP_DEBUG, ("\n"));
-    pbuf_free(p);
+  /* do not forward link-local addresses */
+  if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
+    IP6_STATS_INC(ip6.rterr);
+    IP6_STATS_INC(ip6.drop);
     return;
   }
-  /* Decrement TTL and send ICMP if ttl == 0. */
-  if (--iphdr->hoplim == 0) {
-#if LWIP_ICMP
+
+  /* Find network interface where to forward this IP packet to. */
+  netif = ip6_route(IP6_ADDR_ANY, ip6_current_dest_addr());
+  if (netif == NULL) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+        IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
+        IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
+#if LWIP_ICMP6
     /* Don't send ICMP messages in response to ICMP messages */
-    if (iphdr->nexthdr != IP_PROTO_ICMP) {
-      icmp_time_exceeded(p, ICMP_TE_TTL);
+    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
+      icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
     }
-#endif /* LWIP_ICMP */
-    pbuf_free(p);
+#endif /* LWIP_ICMP6 */
+    IP6_STATS_INC(ip6.rterr);
+    IP6_STATS_INC(ip6.drop);
+    return;
+  }
+  /* Do not forward packets onto the same network interface on which
+   * they arrived. */
+  if (netif == inp) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n"));
+    IP6_STATS_INC(ip6.rterr);
+    IP6_STATS_INC(ip6.drop);
     return;
   }
 
-  /* Incremental update of the IP checksum. */
-  /*  if (iphdr->chksum >= htons(0xffff - 0x100)) {
-    iphdr->chksum += htons(0x100) + 1;
-  } else {
-    iphdr->chksum += htons(0x100);
-    }*/
-
-
-  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));
-#if IP_DEBUG
-  ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-#endif /* IP_DEBUG */
-  LWIP_DEBUGF(IP_DEBUG, ("\n"));
-
-  IP_STATS_INC(ip.fw);
-  IP_STATS_INC(ip.xmit);
+  /* decrement HL */
+  IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1);
+  /* send ICMP6 if HL == 0 */
+  if (IP6H_HOPLIM(iphdr) == 0) {
+#if LWIP_ICMP6
+    /* Don't send ICMP messages in response to ICMP messages */
+    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
+      icmp6_time_exceeded(p, ICMP6_TE_HL);
+    }
+#endif /* LWIP_ICMP6 */
+    IP6_STATS_INC(ip6.drop);
+    return;
+  }
 
-  PERF_STOP("ip_forward");
+  if (netif->mtu && (p->tot_len > netif->mtu)) {
+#if LWIP_ICMP6
+    /* Don't send ICMP messages in response to ICMP messages */
+    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
+      icmp6_packet_too_big(p, netif->mtu);
+    }
+#endif /* LWIP_ICMP6 */
+    IP6_STATS_INC(ip6.drop);
+    return;
+  }
 
-  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
+  LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+      IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
+      IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
+
+  /* transmit pbuf on chosen interface */
+  netif->output_ip6(netif, p, ip6_current_dest_addr());
+  IP6_STATS_INC(ip6.fw);
+  IP6_STATS_INC(ip6.xmit);
+  return;
 }
+#endif /* LWIP_IPV6_FORWARD */
 
-/* ip_input:
- *
- * This function is called by the network interface device driver when an IP packet is
- * received. The function does the basic checks of the IP header such as packet size
- * being at least larger than the header size etc. If the packet was not destined for
- * us, the packet is forwarded (using ip_forward). The IP checksum is always checked.
+
+/**
+ * This function is called by the network interface device driver when
+ * an IPv6 packet is received. The function does the basic checks of the
+ * IP header such as packet size being at least larger than the header
+ * size etc. If the packet was not destined for us, the packet is
+ * forwarded (using ip6_forward).
  *
  * Finally, the packet is sent to the upper layer protocol input function.
+ *
+ * @param p the received IPv6 packet (p->payload points to IPv6 header)
+ * @param inp the netif on which this packet was received
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
+ *         processed, but currently always returns ERR_OK)
  */
-
-void
-ip_input(struct pbuf *p, struct netif *inp) {
-  struct ip_hdr *iphdr;
+err_t
+ip6_input(struct pbuf *p, struct netif *inp)
+{
+  struct ip6_hdr *ip6hdr;
   struct netif *netif;
+  u8_t nexth;
+  u16_t hlen; /* the current header length */
+  u8_t i;
+#if IP_ACCEPT_LINK_LAYER_ADDRESSING
+  int check_ip_src=1;
+#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
 
-
-  PERF_START;
-
-#if IP_DEBUG
-  ip_debug_print(p);
-#endif /* IP_DEBUG */
-
-
-  IP_STATS_INC(ip.recv);
+  IP6_STATS_INC(ip6.recv);
 
   /* identify the IP header */
-  iphdr = p->payload;
-
+  ip6hdr = (struct ip6_hdr *)p->payload;
+  if (IP6H_V(ip6hdr) != 6) {
+    LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U16_F"\n",
+        IP6H_V(ip6hdr)));
+    pbuf_free(p);
+    IP6_STATS_INC(ip6.err);
+    IP6_STATS_INC(ip6.drop);
+    return ERR_OK;
+  }
 
-  if (iphdr->v != 6) {
-    LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
-#if IP_DEBUG
-    ip_debug_print(p);
-#endif /* IP_DEBUG */
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+  if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) {
+    if (IP6_HLEN > p->len) {
+      LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
+            IP6_HLEN, p->len));
+    }
+    if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) {
+      LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+        ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
+            IP6H_PLEN(ip6hdr) + IP6_HLEN, p->tot_len));
+    }
+    /* free (drop) packet pbufs */
     pbuf_free(p);
-    IP_STATS_INC(ip.err);
-    IP_STATS_INC(ip.drop);
-    return;
+    IP6_STATS_INC(ip6.lenerr);
+    IP6_STATS_INC(ip6.drop);
+    return ERR_OK;
   }
 
-  /* is this packet for us? */
-  for(netif = netif_list; netif != NULL; netif = netif->next) {
-#if IP_DEBUG
-    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
-    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-    LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));
-    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
-    LWIP_DEBUGF(IP_DEBUG, ("\n"));
-#endif /* IP_DEBUG */
-    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {
-      break;
+  /* Trim pbuf. This should have been done at the netif layer,
+   * but we'll do it anyway just to be sure that its done. */
+  pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr));
+
+  /* copy IP addresses to aligned ip6_addr_t */
+  ip6_addr_copy(ip_data.current_iphdr_dest.ip6, ip6hdr->dest);
+  ip6_addr_copy(ip_data.current_iphdr_src.ip6, ip6hdr->src);
+
+  /* current header pointer. */
+  ip_data.current_ip6_header = ip6hdr;
+
+  /* match packet against an interface, i.e. is this packet for us? */
+  if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
+    /* Always joined to multicast if-local and link-local all-nodes group. */
+    if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) ||
+        ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) {
+      netif = inp;
+    }
+#if LWIP_IPV6_MLD
+    else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) {
+      netif = inp;
+    }
+#else /* LWIP_IPV6_MLD */
+    else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) {
+      /* Accept all solicited node packets when MLD is not enabled
+       * (for Neighbor discovery). */
+      netif = inp;
+    }
+#endif /* LWIP_IPV6_MLD */
+    else {
+      netif = NULL;
     }
   }
+  else {
+    /* start trying with inp. if that's not acceptable, start walking the
+       list of configured netifs.
+       'first' is used as a boolean to mark whether we started walking the list */
+    int first = 1;
+    netif = inp;
+    do {
+      /* interface is up? */
+      if (netif_is_up(netif)) {
+        /* unicast to this interface address? address configured? */
+        for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+          if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+              ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) {
+            /* exit outer loop */
+            goto netif_found;
+          }
+        }
+      }
+      if (first) {
+        first = 0;
+        netif = netif_list;
+      } else {
+        netif = netif->next;
+      }
+      if (netif == inp) {
+        netif = netif->next;
+      }
+    } while(netif != NULL);
+netif_found:
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n",
+        netif->name[0], netif->name[1]));
+  }
 
+  /* "::" packet source address? (used in duplicate address detection) */
+  if (ip6_addr_isany(ip6_current_src_addr()) &&
+      (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) {
+    /* packet source is not valid */
+    /* free (drop) packet pbufs */
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n"));
+    pbuf_free(p);
+    IP6_STATS_INC(ip6.drop);
+    goto ip6_input_cleanup;
+  }
 
+  /* packet not for us? */
   if (netif == NULL) {
     /* packet not for us, route or discard */
-#if IP_FORWARD
-    ip_forward(p, iphdr);
-#endif
+    LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n"));
+#if LWIP_IPV6_FORWARD
+    /* non-multicast packet? */
+    if (!ip6_addr_ismulticast(ip6_current_dest_addr())) {
+      /* try to forward IP packet on (other) interfaces */
+      ip6_forward(p, ip6hdr, inp);
+    }
+#endif /* LWIP_IPV6_FORWARD */
     pbuf_free(p);
-    return;
+    goto ip6_input_cleanup;
   }
 
-  pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));
+  /* current netif pointer. */
+  ip_data.current_netif = inp;
+
+  /* Save next header type. */
+  nexth = IP6H_NEXTH(ip6hdr);
+
+  /* Init header length. */
+  hlen = ip_data.current_ip_header_tot_len = IP6_HLEN;
+
+  /* Move to payload. */
+  pbuf_header(p, -IP6_HLEN);
+
+  /* Process known option extension headers, if present. */
+  while (nexth != IP6_NEXTH_NONE)
+  {
+    switch (nexth) {
+    case IP6_NEXTH_HOPBYHOP:
+      LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n"));
+      /* Get next header type. */
+      nexth = *((u8_t *)p->payload);
+
+      /* Get the header length. */
+      hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+      ip_data.current_ip_header_tot_len += hlen;
+
+      /* Skip over this header. */
+      if (hlen > p->len) {
+        LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+          ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+              hlen, p->len));
+        /* free (drop) packet pbufs */
+        pbuf_free(p);
+        IP6_STATS_INC(ip6.lenerr);
+        IP6_STATS_INC(ip6.drop);
+        goto ip6_input_cleanup;
+      }
+
+      pbuf_header(p, -hlen);
+      break;
+    case IP6_NEXTH_DESTOPTS:
+      LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n"));
+      /* Get next header type. */
+      nexth = *((u8_t *)p->payload);
+
+      /* Get the header length. */
+      hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+      ip_data.current_ip_header_tot_len += hlen;
+
+      /* Skip over this header. */
+      if (hlen > p->len) {
+        LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+          ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+              hlen, p->len));
+        /* free (drop) packet pbufs */
+        pbuf_free(p);
+        IP6_STATS_INC(ip6.lenerr);
+        IP6_STATS_INC(ip6.drop);
+        goto ip6_input_cleanup;
+      }
+
+      pbuf_header(p, -hlen);
+      break;
+    case IP6_NEXTH_ROUTING:
+      LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n"));
+      /* Get next header type. */
+      nexth = *((u8_t *)p->payload);
+
+      /* Get the header length. */
+      hlen = 8 * (1 + *((u8_t *)p->payload) + 1);
+      ip_data.current_ip_header_tot_len += hlen;
+
+      /* Skip over this header. */
+      if (hlen > p->len) {
+        LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+          ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+              hlen, p->len));
+        /* free (drop) packet pbufs */
+        pbuf_free(p);
+        IP6_STATS_INC(ip6.lenerr);
+        IP6_STATS_INC(ip6.drop);
+        goto ip6_input_cleanup;
+      }
+
+      pbuf_header(p, -hlen);
+      break;
 
-  /* send to upper layers */
-#if IP_DEBUG
-  /*  LWIP_DEBUGF("ip_input: \n");
-  ip_debug_print(p);
-  LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
-#endif /* IP_DEBUG */
-
-  if(pbuf_header(p, -IP_HLEN)) {
-    LWIP_ASSERT("Can't move over header in packet", 0);
-    return;
+    case IP6_NEXTH_FRAGMENT:
+    {
+      struct ip6_frag_hdr * frag_hdr;
+      LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n"));
+
+      frag_hdr = (struct ip6_frag_hdr *)p->payload;
+
+      /* Get next header type. */
+      nexth = frag_hdr->_nexth;
+
+      /* Fragment Header length. */
+      hlen = 8;
+      ip_data.current_ip_header_tot_len += hlen;
+
+      /* Make sure this header fits in current pbuf. */
+      if (hlen > p->len) {
+        LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+          ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n",
+              hlen, p->len));
+        /* free (drop) packet pbufs */
+        pbuf_free(p);
+        IP6_FRAG_STATS_INC(ip6_frag.lenerr);
+        IP6_FRAG_STATS_INC(ip6_frag.drop);
+        goto ip6_input_cleanup;
+      }
+
+      /* Offset == 0 and more_fragments == 0? */
+      if (((frag_hdr->_fragment_offset & IP6_FRAG_OFFSET_MASK) == 0) &&
+          ((frag_hdr->_fragment_offset & IP6_FRAG_MORE_FLAG) == 0)) {
+
+        /* This is a 1-fragment packet, usually a packet that we have
+         * already reassembled. Skip this header anc continue. */
+        pbuf_header(p, -hlen);
+      }
+      else {
+#if LWIP_IPV6_REASS
+
+        /* reassemble the packet */
+        p = ip6_reass(p);
+        /* packet not fully reassembled yet? */
+        if (p == NULL) {
+          goto ip6_input_cleanup;
+        }
+
+        /* Returned p point to IPv6 header.
+         * Update all our variables and pointers and continue. */
+        ip6hdr = (struct ip6_hdr *)p->payload;
+        nexth = IP6H_NEXTH(ip6hdr);
+        hlen = ip_data.current_ip_header_tot_len = IP6_HLEN;
+        pbuf_header(p, -IP6_HLEN);
+
+#else /* LWIP_IPV6_REASS */
+        /* free (drop) packet pbufs */
+        LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n"));
+        pbuf_free(p);
+        IP6_STATS_INC(ip6.opterr);
+        IP6_STATS_INC(ip6.drop);
+        goto ip6_input_cleanup;
+#endif /* LWIP_IPV6_REASS */
+      }
+      break;
+    }
+    default:
+      goto options_done;
+      break;
+    }
   }
+options_done:
+
+  /* p points to IPv6 header again. */
+  pbuf_header(p, ip_data.current_ip_header_tot_len);
 
-  switch (iphdr->nexthdr) {
-  case IP_PROTO_UDP:
-    udp_input(p, inp);
-    break;
-  case IP_PROTO_TCP:
-    tcp_input(p, inp);
-    break;
-#if LWIP_ICMP
-  case IP_PROTO_ICMP:
-    icmp_input(p, inp);
-    break;
+  /* send to upper layers */
+  LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n"));
+  ip6_debug_print(p);
+  LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
+
+#if LWIP_RAW
+  /* raw input did not eat the packet? */
+  if (raw_input(p, inp) == 0)
+#endif /* LWIP_RAW */
+  {
+    switch (nexth) {
+    case IP6_NEXTH_NONE:
+      pbuf_free(p);
+      break;
+#if LWIP_UDP
+    case IP6_NEXTH_UDP:
+#if LWIP_UDPLITE
+    case IP6_NEXTH_UDPLITE:
+#endif /* LWIP_UDPLITE */
+      /* Point to payload. */
+      pbuf_header(p, -ip_data.current_ip_header_tot_len);
+      udp_input(p, inp);
+      break;
+#endif /* LWIP_UDP */
+#if LWIP_TCP
+    case IP6_NEXTH_TCP:
+      /* Point to payload. */
+      pbuf_header(p, -ip_data.current_ip_header_tot_len);
+      tcp_input(p, inp);
+      break;
+#endif /* LWIP_TCP */
+#if LWIP_ICMP6
+    case IP6_NEXTH_ICMP6:
+      /* Point to payload. */
+      pbuf_header(p, -ip_data.current_ip_header_tot_len);
+      icmp6_input(p, inp);
+      break;
 #endif /* LWIP_ICMP */
-  default:
-#if LWIP_ICMP
-    /* send ICMP destination protocol unreachable */
-    icmp_dest_unreach(p, ICMP_DUR_PROTO);
+    default:
+#if LWIP_ICMP6
+      /* send ICMP parameter problem unless it was a multicast or ICMPv6 */
+      if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) &&
+          (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) {
+        icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen);
+      }
 #endif /* LWIP_ICMP */
-    pbuf_free(p);
-    LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n",
-          iphdr->nexthdr));
-
-    IP_STATS_INC(ip.proterr);
-    IP_STATS_INC(ip.drop);
+      LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr)));
+      pbuf_free(p);
+      IP6_STATS_INC(ip6.proterr);
+      IP6_STATS_INC(ip6.drop);
+      break;
+    }
   }
-  PERF_STOP("ip_input");
+
+ip6_input_cleanup:
+  ip_data.current_netif = NULL;
+  ip_data.current_ip6_header = NULL;
+  ip_data.current_ip_header_tot_len = 0;
+  ip6_addr_set_any(&ip_data.current_iphdr_src.ip6);
+  ip6_addr_set_any(&ip_data.current_iphdr_dest.ip6);
+
+  return ERR_OK;
 }
 
 
-/* ip_output_if:
+/**
+ * Sends an IPv6 packet on a network interface. This function constructs
+ * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is
+ * used as source (usually during network startup). If the source IPv6 address it
+ * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network
+ * interface is filled in as source address. If the destination IPv6 address is
+ * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points
+ * to it instead of the data.
  *
- * Sends an IP packet on a network interface. This function constructs the IP header
- * and calculates the IP header checksum. If the source IP address is NULL,
- * the IP address of the outgoing network interface is filled in as source address.
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an
+            IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ *         IP address of the netif is selected and used as source address.
+ *         if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
+ * @param netif the netif on which to send this packet
+ * @return ERR_OK if the packet was sent OK
+ *         ERR_BUF if p doesn't have enough space for IPv6/LINK headers
+ *         returns errors returned by netif->output
  */
-
 err_t
-ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
-       u8_t ttl,
-       u8_t proto, struct netif *netif)
+ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+             u8_t hl, u8_t tc,
+             u8_t nexth, struct netif *netif)
 {
-  struct ip_hdr *iphdr;
+  struct ip6_hdr *ip6hdr;
+  ip6_addr_t dest_addr;
 
-  PERF_START;
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  /* Should the IPv6 header be generated or is it already included in p? */
+  if (dest != IP_HDRINCL) {
+    /* generate IPv6 header */
+    if (pbuf_header(p, IP6_HLEN)) {
+      LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n"));
+      IP6_STATS_INC(ip6.err);
+      return ERR_BUF;
+    }
 
-  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));
-  if (pbuf_header(p, IP_HLEN)) {
-    LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));
-    IP_STATS_INC(ip.err);
+    ip6hdr = (struct ip6_hdr *)p->payload;
+    LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr",
+               (p->len >= sizeof(struct ip6_hdr)));
 
-    return ERR_BUF;
-  }
-  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));
+    IP6H_HOPLIM_SET(ip6hdr, hl);
+    IP6H_NEXTH_SET(ip6hdr, nexth);
 
-  iphdr = p->payload;
+    /* dest cannot be NULL here */
+    ip6_addr_copy(ip6hdr->dest, *dest);
 
+    IP6H_VTCFL_SET(ip6hdr, 6, tc, 0);
+    IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN);
 
-  if (dest != IP_HDRINCL) {
-    LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n"));
-    iphdr->hoplim = ttl;
-    iphdr->nexthdr = proto;
-    iphdr->len = htons(p->tot_len - IP_HLEN);
-    ip_addr_set(&(iphdr->dest), dest);
-
-    iphdr->v = 6;
-
-    if (ip_addr_isany(src)) {
-      ip_addr_set(&(iphdr->src), &(netif->ip_addr));
-    } else {
-      ip_addr_set(&(iphdr->src), src);
+    if (src == NULL) {
+      src = IP6_ADDR_ANY;
+    }
+    else if (ip6_addr_isany(src)) {
+      src = ip6_select_source_address(netif, dest);
+      if ((src == NULL) || ip6_addr_isany(src)) {
+        /* No appropriate source address was found for this packet. */
+        LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n"));
+        IP6_STATS_INC(ip6.rterr);
+        return ERR_RTE;
+      }
     }
+    /* src cannot be NULL here */
+    ip6_addr_copy(ip6hdr->src, *src);
 
   } else {
-    dest = &(iphdr->dest);
+    /* IP header already included in p */
+    ip6hdr = (struct ip6_hdr *)p->payload;
+    ip6_addr_copy(dest_addr, ip6hdr->dest);
+    dest = &dest_addr;
   }
 
-  IP_STATS_INC(ip.xmit);
-
-  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len));
-#if IP_DEBUG
-  ip_debug_print(p);
-#endif /* IP_DEBUG */
+  IP6_STATS_INC(ip6.xmit);
+
+  LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
+  ip6_debug_print(p);
+
+#if ENABLE_LOOPBACK
+  /* TODO implement loopback for v6
+  if (ip6_addr_cmp(dest, netif_ip6_addr(0))) {
+    return netif_loop_output(netif, p, dest);
+  }*/
+#endif /* ENABLE_LOOPBACK */
+#if LWIP_IPV6_FRAG
+  /* don't fragment if interface has mtu set to 0 [loopif] */
+  if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) {
+    return ip6_frag(p, netif, dest);
+  }
+#endif /* LWIP_IPV6_FRAG */
 
-  PERF_STOP("ip_output_if");
-  return netif->output(netif, p, dest);
+  LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()"));
+  return netif->output_ip6(netif, p, dest);
 }
 
-/* ip_output:
+/**
+ * Simple interface to ip6_output_if. It finds the outgoing network
+ * interface and calls upon ip6_output_if to do the actual work.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an
+            IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ *         IP address of the netif is selected and used as source address.
+ *         if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
  *
- * Simple interface to ip_output_if. It finds the outgoing network interface and
- * calls upon ip_output_if to do the actual work.
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
  */
-
 err_t
-ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
-    u8_t ttl, u8_t proto)
+ip6_output(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+          u8_t hl, u8_t tc, u8_t nexth)
 {
   struct netif *netif;
-  if ((netif = ip_route(dest)) == NULL) {
-    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
-    IP_STATS_INC(ip.rterr);
+
+  /* pbufs passed to IPv6 must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip6_route(src, dest)) == NULL) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+        IP6_ADDR_BLOCK1(dest),
+        IP6_ADDR_BLOCK2(dest),
+        IP6_ADDR_BLOCK3(dest),
+        IP6_ADDR_BLOCK4(dest),
+        IP6_ADDR_BLOCK5(dest),
+        IP6_ADDR_BLOCK6(dest),
+        IP6_ADDR_BLOCK7(dest),
+        IP6_ADDR_BLOCK8(dest)));
+    IP6_STATS_INC(ip6.rterr);
     return ERR_RTE;
   }
 
-  return ip_output_if (p, src, dest, ttl, proto, netif);
+  return ip6_output_if(p, src, dest, hl, tc, nexth, netif);
 }
 
+
 #if LWIP_NETIF_HWADDRHINT
+/** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
+ *  before calling ip6_output_if.
+ *
+ * @param p the packet to send (p->payload points to the data, e.g. next
+            protocol header; if dest == IP_HDRINCL, p already includes an
+            IPv6 header and p->payload points to that IPv6 header)
+ * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an
+ *         IP address of the netif is selected and used as source address.
+ *         if src == NULL, IP6_ADDR_ANY is used as source)
+ * @param dest the destination IPv6 address to send the packet to
+ * @param hl the Hop Limit value to be set in the IPv6 header
+ * @param tc the Traffic Class value to be set in the IPv6 header
+ * @param nexth the Next Header to be set in the IPv6 header
+ * @param addr_hint address hint pointer set to netif->addr_hint before
+ *        calling ip_output_if()
+ *
+ * @return ERR_RTE if no route is found
+ *         see ip_output_if() for more return values
+ */
 err_t
-ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
-          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
+ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+          u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint)
 {
   struct netif *netif;
   err_t err;
 
-  if ((netif = ip_route(dest)) == NULL) {
-    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
-    IP_STATS_INC(ip.rterr);
+  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer
+     gets altered as the packet is passed down the stack */
+  LWIP_ASSERT("p->ref == 1", p->ref == 1);
+
+  if ((netif = ip6_route(src, dest)) == NULL) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
+        IP6_ADDR_BLOCK1(dest),
+        IP6_ADDR_BLOCK2(dest),
+        IP6_ADDR_BLOCK3(dest),
+        IP6_ADDR_BLOCK4(dest),
+        IP6_ADDR_BLOCK5(dest),
+        IP6_ADDR_BLOCK6(dest),
+        IP6_ADDR_BLOCK7(dest),
+        IP6_ADDR_BLOCK8(dest)));
+    IP6_STATS_INC(ip6.rterr);
     return ERR_RTE;
   }
 
-  netif->addr_hint = addr_hint;
-  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
-  netif->addr_hint = NULL;
+  NETIF_SET_HWADDRHINT(netif, addr_hint);
+  err = ip6_output_if(p, src, dest, hl, tc, nexth, netif);
+  NETIF_SET_HWADDRHINT(netif, NULL);
 
   return err;
 }
 #endif /* LWIP_NETIF_HWADDRHINT*/
 
-#if IP_DEBUG
+#if LWIP_IPV6_MLD
+/**
+ * Add a hop-by-hop options header with a router alert option and padding.
+ *
+ * Used by MLD when sending a Multicast listener report/done message.
+ *
+ * @param p the packet to which we will prepend the options header
+ * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6)
+ * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD)
+ * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise
+ */
+err_t
+ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value)
+{
+  struct ip6_hbh_hdr * hbh_hdr;
+
+  /* Move pointer to make room for hop-by-hop options header. */
+  if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) {
+    LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n"));
+    IP6_STATS_INC(ip6.err);
+    return ERR_BUF;
+  }
+
+  hbh_hdr = (struct ip6_hbh_hdr *)p->payload;
+
+  /* Set fields. */
+  hbh_hdr->_nexth = nexth;
+  hbh_hdr->_hlen = 0;
+  hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION;
+  hbh_hdr->_ra_opt_dlen = 2;
+  hbh_hdr->_ra_opt_data = value;
+  hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION;
+  hbh_hdr->_padn_opt_dlen = 0;
+
+  return ERR_OK;
+}
+#endif /* LWIP_IPV6_MLD */
+
+#if IP6_DEBUG
+/* Print an IPv6 header by using LWIP_DEBUGF
+ * @param p an IPv6 packet, p->payload pointing to the IPv6 header
+ */
 void
-ip_debug_print(struct pbuf *p)
+ip6_debug_print(struct pbuf *p)
 {
-  struct ip_hdr *iphdr = p->payload;
-
-  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |  %"X16_F"%"X16_F"  |      %"X16_F"%"X16_F"           | (v, traffic class, flow label)\n",
-        iphdr->v,
-        iphdr->tclass1, iphdr->tclass2,
-        iphdr->flow1, iphdr->flow2));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      | %2"U16_F"  |  %2"U16_F"   | (len, nexthdr, hoplim)\n",
-        ntohs(iphdr->len),
-        iphdr->nexthdr,
-        iphdr->hoplim));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",
-        (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff,
-        ntohl(iphdr->src.addr[0]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",
-        (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff,
-        ntohl(iphdr->src.addr[1]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",
-        (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff,
-        ntohl(iphdr->src.addr[2]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",
-        (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff,
-        ntohl(iphdr->src.addr[3]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",
-        (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff,
-        ntohl(iphdr->dest.addr[0]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",
-        (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff,
-        ntohl(iphdr->dest.addr[1]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",
-        (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff,
-        ntohl(iphdr->dest.addr[2]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",
-        (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff,
-        ntohl(iphdr->dest.addr[3]) & 0xffff));
-  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
+  struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
+
+  LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n"));
+  LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" |  %3"U16_F"  |      %7"U32_F"     | (ver, class, flow)\n",
+                    IP6H_V(ip6hdr),
+                    IP6H_TC(ip6hdr),
+                    IP6H_FL(ip6hdr)));
+  LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP6_DEBUG, ("|     %5"U16_F"     |  %3"U16_F"  |  %3"U16_F"  | (plen, nexth, hopl)\n",
+                    ntohs(IP6H_PLEN(ip6hdr)),
+                    ntohs(IP6H_NEXTH(ip6hdr)),
+                    ntohs(IP6H_HOPLIM(ip6hdr))));
+  LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP6_DEBUG, ("|  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |  %4"X32_F" | (src)\n",
+                    IP6_ADDR_BLOCK1(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK2(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK3(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK4(&(ip6hdr->src))));
+  LWIP_DEBUGF(IP6_DEBUG, ("|  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |\n",
+                    IP6_ADDR_BLOCK5(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK6(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK7(&(ip6hdr->src)),
+                    IP6_ADDR_BLOCK8(&(ip6hdr->src))));
+  LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
+  LWIP_DEBUGF(IP6_DEBUG, ("|  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |  %4"X32_F" | (dest)\n",
+                    IP6_ADDR_BLOCK1(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK2(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK3(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK4(&(ip6hdr->dest))));
+  LWIP_DEBUGF(IP6_DEBUG, ("|  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |  %4"X32_F" |\n",
+                    IP6_ADDR_BLOCK5(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK6(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK7(&(ip6hdr->dest)),
+                    IP6_ADDR_BLOCK8(&(ip6hdr->dest))));
+  LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n"));
 }
-#endif /* IP_DEBUG */
+#endif /* IP6_DEBUG */
+
+#endif /* LWIP_IPV6 */
index 2da6cea4276b7aca1094229a6d2aab48a00df1c6..6c047491cd1b1a760af48fe4eab227c95b25387d 100644 (file)
@@ -1,5 +1,11 @@
+/**
+ * @file
+ *
+ * IPv6 addresses.
+ */
+
 /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * Copyright (c) 2010 Inico Technologies Ltd.
  * All rights reserved. 
  * 
  * Redistribution and use in source and binary forms, with or without modification, 
  *
  * This file is part of the lwIP TCP/IP stack.
  * 
- * Author: Adam Dunkels <adam@sics.se>
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ * Functions for handling IPv6 addresses.
  *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
  */
 
 #include "lwip/opt.h"
-#include "lwip/ip_addr.h"
-#include "lwip/inet.h"
 
-u8_t
-ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
-                struct ip_addr *mask)
-{
-  return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
-         (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
-         (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
-         (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
-        
-}
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/ip6_addr.h"
+#include "lwip/def.h"
+
+/* used by IP6_ADDR_ANY in ip6_addr.h */
+const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
 
-u8_t
-ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
+#ifndef isprint
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)
+#define isprint(c)           in_range(c, 0x20, 0x7f)
+#define isdigit(c)           in_range(c, '0', '9')
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
+#define islower(c)           in_range(c, 'a', 'z')
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
+#define xchar(i)             ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
+#endif
+
+/**
+ * Check whether "cp" is a valid ascii representation
+ * of an IPv6 address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ *
+ * @param cp IPv6 address in ascii represenation (e.g. "FF01::1")
+ * @param addr pointer to which to save the ip address in network order
+ * @return 1 if cp could be converted to addr, 0 on failure
+ */
+int
+ip6addr_aton(const char *cp, ip6_addr_t *addr)
 {
-  return(addr1->addr[0] == addr2->addr[0] &&
-         addr1->addr[1] == addr2->addr[1] &&
-         addr1->addr[2] == addr2->addr[2] &&
-         addr1->addr[3] == addr2->addr[3]);
+  u32_t addr_index, zero_blocks, current_block_index, current_block_value;
+  const char * s;
+
+  /* Count the number of colons, to count the number of blocks in a "::" sequence
+     zero_blocks may be 1 even if there are no :: sequences */
+  zero_blocks = 8;
+  for (s = cp; *s != 0; s++) {
+    if (*s == ':')
+      zero_blocks--;
+    else if (!isxdigit(*s))
+      break;
+  }
+
+  /* parse each block */
+  addr_index = 0;
+  current_block_index = 0;
+  current_block_value = 0;
+  for (s = cp; *s != 0; s++) {
+    if (*s == ':') {
+      if (current_block_index & 0x1) {
+        addr->addr[addr_index++] |= current_block_value;
+      }
+      else {
+        addr->addr[addr_index] = current_block_value << 16;
+      }
+      current_block_index++;
+      current_block_value = 0;
+      if (current_block_index > 7) {
+        /* address too long! */
+        return 0;
+      } if (s[1] == ':') {
+        s++;
+        /* "::" found, set zeros */
+        while (zero_blocks-- > 0) {
+          if (current_block_index & 0x1) {
+            addr_index++;
+          }
+          else {
+            addr->addr[addr_index] = 0;
+          }
+          current_block_index++;
+        }
+      }
+    } else if (isxdigit(*s)) {
+      /* add current digit */
+      current_block_value = (current_block_value << 4) +
+          (isdigit(*s) ? *s - '0' :
+          10 + (islower(*s) ? *s - 'a' : *s - 'A'));
+    } else {
+      /* unexpected digit, space? CRLF? */
+      break;
+    }
+  }
+
+  if (current_block_index & 0x1) {
+    addr->addr[addr_index++] |= current_block_value;
+  }
+  else {
+    addr->addr[addr_index] = current_block_value << 16;
+  }
+
+  /* convert to network byte order. */
+  for (addr_index = 0; addr_index < 4; addr_index++) {
+    addr->addr[addr_index] = htonl(addr->addr[addr_index]);
+  }
+
+  if (current_block_index != 7) {
+    return 0;
+  }
+
+  return 1;
+
 }
 
-void
-ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
+/**
+ * Convert numeric IPv6 address into ASCII representation.
+ * returns ptr to static buffer; not reentrant!
+ *
+ * @param addr ip6 address in network order to convert
+ * @return pointer to a global static (!) buffer that holds the ASCII
+ *         represenation of addr
+ */
+char *
+ip6addr_ntoa(const ip6_addr_t *addr)
 {
-  SMEMCPY(dest, src, sizeof(struct ip_addr));
-  /*  dest->addr[0] = src->addr[0];
-  dest->addr[1] = src->addr[1];
-  dest->addr[2] = src->addr[2];
-  dest->addr[3] = src->addr[3];*/
+  static char str[40];
+  return ip6addr_ntoa_r(addr, str, 40);
 }
 
-u8_t
-ip_addr_isany(struct ip_addr *addr)
+/**
+ * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
+ *
+ * @param addr ip6 address in network order to convert
+ * @param buf target buffer where the string is stored
+ * @param buflen length of buf
+ * @return either pointer to buf which now holds the ASCII
+ *         representation of addr or NULL if buf was too small
+ */
+char *
+ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
 {
-  if (addr == NULL) return 1;
-  return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
+  u32_t current_block_index, current_block_value;
+  s32_t zero_flag, i;
+
+  i = 0;
+  zero_flag = 0; /* used to indicate a zero chain for "::' */
+
+  for (current_block_index = 0; current_block_index < 8; current_block_index++) {
+    /* get the current 16-bit block */
+    current_block_value = htonl(addr->addr[current_block_index >> 1]);
+    if ((current_block_index & 0x1) == 0) {
+      current_block_value = current_block_value >> 16;
+    }
+    current_block_value &= 0xffff;
+
+    if (current_block_value == 0) {
+      /* generate empty block "::" */
+      if (!zero_flag) {
+        if (current_block_index > 0) {
+          zero_flag = 1;
+          buf[i++] = ':';
+          if (i >= buflen) return NULL;
+        }
+      }
+    }
+    else {
+      if (current_block_index > 0) {
+        buf[i++] = ':';
+        if (i >= buflen) return NULL;
+      }
+
+      if ((current_block_value & 0xf000) == 0) {
+        zero_flag = 1;
+      }
+      else {
+        buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
+        zero_flag = 0;
+        if (i >= buflen) return NULL;
+      }
+
+      if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
+        /* do nothing */
+      }
+      else {
+        buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
+        zero_flag = 0;
+        if (i >= buflen) return NULL;
+      }
+
+      if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
+        /* do nothing */
+      }
+      else {
+        buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
+        zero_flag = 0;
+        if (i >= buflen) return NULL;
+      }
+
+      buf[i++] = xchar((current_block_value & 0xf));
+      if (i >= buflen) return NULL;
+
+      zero_flag = 0;
+    }
+  }
+
+  buf[i] = 0;
+
+  return buf;
 }
+#endif /* LWIP_IPV6 */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ip6_frag.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/ip6_frag.c
new file mode 100644 (file)
index 0000000..f33f4fb
--- /dev/null
@@ -0,0 +1,689 @@
+/**
+ * @file
+ *
+ * IPv6 fragmentation and reassembly.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip6_frag.h"
+#include "lwip/ip6.h"
+#include "lwip/icmp6.h"
+#include "lwip/nd6.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/memp.h"
+#include "lwip/stats.h"
+
+#include <string.h>
+
+#if LWIP_IPV6 && LWIP_IPV6_REASS  /* don't build if not configured for use in lwipopts.h */
+
+
+/** Setting this to 0, you can turn off checking the fragments for overlapping
+ * regions. The code gets a little smaller. Only use this if you know that
+ * overlapping won't occur on your network! */
+#ifndef IP_REASS_CHECK_OVERLAP
+#define IP_REASS_CHECK_OVERLAP 1
+#endif /* IP_REASS_CHECK_OVERLAP */
+
+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
+ * is set to 1, so one datagram can be reassembled at a time, only. */
+#ifndef IP_REASS_FREE_OLDEST
+#define IP_REASS_FREE_OLDEST 1
+#endif /* IP_REASS_FREE_OLDEST */
+
+#define IP_REASS_FLAG_LASTFRAG 0x01
+
+/** This is a helper struct which holds the starting
+ * offset and the ending offset of this fragment to
+ * easily chain the fragments.
+ * It has the same packing requirements as the IPv6 header, since it replaces
+ * the Fragment Header in memory in incoming fragments to keep
+ * track of the various fragments.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip6_reass_helper {
+  PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
+  PACK_STRUCT_FIELD(u16_t start);
+  PACK_STRUCT_FIELD(u16_t end);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* static variables */
+static struct ip6_reassdata *reassdatagrams;
+static u16_t ip6_reass_pbufcount;
+
+/* Forward declarations. */
+static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr);
+#if IP_REASS_FREE_OLDEST
+static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed);
+#endif /* IP_REASS_FREE_OLDEST */
+
+void
+ip6_reass_tmr(void)
+{
+  struct ip6_reassdata *r, *tmp;
+
+  r = reassdatagrams;
+  while (r != NULL) {
+    /* Decrement the timer. Once it reaches 0,
+     * clean up the incomplete fragment assembly */
+    if (r->timer > 0) {
+      r->timer--;
+      r = r->next;
+    } else {
+      /* reassembly timed out */
+      tmp = r;
+      /* get the next pointer before freeing */
+      r = r->next;
+      /* free the helper struct and all enqueued pbufs */
+      ip6_reass_free_complete_datagram(tmp);
+     }
+   }
+}
+
+/**
+ * Free a datagram (struct ip6_reassdata) and all its pbufs.
+ * Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
+ * sends an ICMP time exceeded packet.
+ *
+ * @param ipr datagram to free
+ */
+static void
+ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
+{
+  struct ip6_reassdata *prev;
+  u16_t pbufs_freed = 0;
+  u8_t clen;
+  struct pbuf *p;
+  struct ip6_reass_helper *iprh;
+
+#if LWIP_ICMP6
+  iprh = (struct ip6_reass_helper *)ipr->p->payload;
+  if (iprh->start == 0) {
+    /* The first fragment was received, send ICMP time exceeded. */
+    /* First, de-queue the first pbuf from r->p. */
+    p = ipr->p;
+    ipr->p = iprh->next_pbuf;
+    /* Then, move back to the original header (we are now pointing to Fragment header). */
+    pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
+    icmp6_time_exceeded(p, ICMP6_TE_FRAG);
+    clen = pbuf_clen(p);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(p);
+  }
+#endif /* LWIP_ICMP6 */
+
+  /* First, free all received pbufs.  The individual pbufs need to be released
+     separately as they have not yet been chained */
+  p = ipr->p;
+  while (p != NULL) {
+    struct pbuf *pcur;
+    iprh = (struct ip6_reass_helper *)p->payload;
+    pcur = p;
+    /* get the next pointer before freeing */
+    p = iprh->next_pbuf;
+    clen = pbuf_clen(pcur);
+    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
+    pbufs_freed += clen;
+    pbuf_free(pcur);
+  }
+
+  /* Then, unchain the struct ip6_reassdata from the list and free it. */
+  if (ipr == reassdatagrams) {
+    reassdatagrams = ipr->next;
+  } else {
+    prev = reassdatagrams;
+    while (prev != NULL) {
+      if (prev->next == ipr) {
+        break;
+      }
+      prev = prev->next;
+    }
+    if (prev != NULL) {
+      prev->next = ipr->next;
+    }
+  }
+  memp_free(MEMP_IP6_REASSDATA, ipr);
+
+  /* Finally, update number of pbufs in reassembly queue */
+  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
+  ip6_reass_pbufcount -= pbufs_freed;
+}
+
+#if IP_REASS_FREE_OLDEST
+/**
+ * Free the oldest datagram to make room for enqueueing new fragments.
+ * The datagram ipr is not freed!
+ *
+ * @param ipr ip6_reassdata for the current fragment
+ * @param pbufs_needed number of pbufs needed to enqueue
+ *        (used for freeing other datagrams if not enough space)
+ */
+static void
+ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed)
+{
+  struct ip6_reassdata *r, *oldest;
+
+  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
+   * but don't free the current datagram! */
+  do {
+    r = oldest = reassdatagrams;
+    while (r != NULL) {
+      if (r != ipr) {
+        if (r->timer <= oldest->timer) {
+          /* older than the previous oldest */
+          oldest = r;
+        }
+      }
+      r = r->next;
+    }
+    if (oldest != NULL) {
+      ip6_reass_free_complete_datagram(oldest);
+    }
+  } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL));
+}
+#endif /* IP_REASS_FREE_OLDEST */
+
+/**
+ * Reassembles incoming IPv6 fragments into an IPv6 datagram.
+ *
+ * @param p points to the IPv6 Fragment Header
+ * @param len the length of the payload (after Fragment Header)
+ * @return NULL if reassembly is incomplete, pbuf pointing to
+ *         IPv6 Header if reassembly is complete
+ */
+struct pbuf *
+ip6_reass(struct pbuf *p)
+{
+  struct ip6_reassdata *ipr, *ipr_prev;
+  struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
+  struct ip6_frag_hdr * frag_hdr;
+  u16_t offset, len;
+  u8_t clen, valid = 1;
+  struct pbuf *q;
+
+  IP6_FRAG_STATS_INC(ip6_frag.recv);
+
+  frag_hdr = (struct ip6_frag_hdr *) p->payload;
+
+  clen = pbuf_clen(p);
+
+  offset = ntohs(frag_hdr->_fragment_offset);
+
+  /* Calculate fragment length from IPv6 payload length.
+   * Adjust for headers before Fragment Header.
+   * And finally adjust by Fragment Header length. */
+  len = ntohs(ip6_current_header()->_plen);
+  len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN;
+  len -= IP6_FRAG_HLEN;
+
+  /* Look for the datagram the fragment belongs to in the current datagram queue,
+   * remembering the previous in the queue for later dequeueing. */
+  for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {
+    /* Check if the incoming fragment matches the one currently present
+       in the reassembly buffer. If so, we proceed with copying the
+       fragment into the buffer. */
+    if ((frag_hdr->_identification == ipr->identification) &&
+        ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) &&
+        ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) {
+      IP6_FRAG_STATS_INC(ip6_frag.cachehit);
+      break;
+    }
+    ipr_prev = ipr;
+  }
+
+  if (ipr == NULL) {
+  /* Enqueue a new datagram into the datagram queue */
+    ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
+    if (ipr == NULL) {
+#if IP_REASS_FREE_OLDEST
+      /* Make room and try again. */
+      ip6_reass_remove_oldest_datagram(ipr, clen);
+      ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
+      if (ipr == NULL)
+#endif /* IP_REASS_FREE_OLDEST */
+      {
+        IP6_FRAG_STATS_INC(ip6_frag.memerr);
+        IP6_FRAG_STATS_INC(ip6_frag.drop);
+        goto nullreturn;
+      }
+    }
+
+    memset(ipr, 0, sizeof(struct ip6_reassdata));
+    ipr->timer = IP_REASS_MAXAGE;
+
+    /* enqueue the new structure to the front of the list */
+    ipr->next = reassdatagrams;
+    reassdatagrams = ipr;
+
+    /* Use the current IPv6 header for src/dest address reference.
+     * Eventually, we will replace it when we get the first fragment
+     * (it might be this one, in any case, it is done later). */
+    ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
+
+    /* copy the fragmented packet id. */
+    ipr->identification = frag_hdr->_identification;
+
+    /* copy the nexth field */
+    ipr->nexth = frag_hdr->_nexth;
+  }
+
+  /* Check if we are allowed to enqueue more datagrams. */
+  if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
+#if IP_REASS_FREE_OLDEST
+    ip6_reass_remove_oldest_datagram(ipr, clen);
+    if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)
+#endif /* IP_REASS_FREE_OLDEST */
+    {
+      /* @todo: send ICMPv6 time exceeded here? */
+      /* drop this pbuf */
+      IP6_FRAG_STATS_INC(ip6_frag.memerr);
+      IP6_FRAG_STATS_INC(ip6_frag.drop);
+      goto nullreturn;
+    }
+  }
+
+  /* Overwrite Fragment Header with our own helper struct. */
+  iprh = (struct ip6_reass_helper *)p->payload;
+  iprh->next_pbuf = NULL;
+  iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
+  iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
+
+  /* find the right place to insert this pbuf */
+  /* Iterate through until we either get to the end of the list (append),
+   * or we find on with a larger offset (insert). */
+  for (q = ipr->p; q != NULL;) {
+    iprh_tmp = (struct ip6_reass_helper*)q->payload;
+    if (iprh->start < iprh_tmp->start) {
+#if IP_REASS_CHECK_OVERLAP
+      if (iprh->end > iprh_tmp->start) {
+        /* fragment overlaps with following, throw away */
+        IP6_FRAG_STATS_INC(ip6_frag.proterr);
+        IP6_FRAG_STATS_INC(ip6_frag.drop);
+        goto nullreturn;
+      }
+      if (iprh_prev != NULL) {
+        if (iprh->start < iprh_prev->end) {
+          /* fragment overlaps with previous, throw away */
+          IP6_FRAG_STATS_INC(ip6_frag.proterr);
+          IP6_FRAG_STATS_INC(ip6_frag.drop);
+          goto nullreturn;
+        }
+      }
+#endif /* IP_REASS_CHECK_OVERLAP */
+      /* the new pbuf should be inserted before this */
+      iprh->next_pbuf = q;
+      if (iprh_prev != NULL) {
+        /* not the fragment with the lowest offset */
+        iprh_prev->next_pbuf = p;
+      } else {
+        /* fragment with the lowest offset */
+        ipr->p = p;
+      }
+      break;
+    } else if(iprh->start == iprh_tmp->start) {
+      /* received the same datagram twice: no need to keep the datagram */
+      IP6_FRAG_STATS_INC(ip6_frag.drop);
+      goto nullreturn;
+#if IP_REASS_CHECK_OVERLAP
+    } else if(iprh->start < iprh_tmp->end) {
+      /* overlap: no need to keep the new datagram */
+      IP6_FRAG_STATS_INC(ip6_frag.proterr);
+      IP6_FRAG_STATS_INC(ip6_frag.drop);
+      goto nullreturn;
+#endif /* IP_REASS_CHECK_OVERLAP */
+    } else {
+      /* Check if the fragments received so far have no gaps. */
+      if (iprh_prev != NULL) {
+        if (iprh_prev->end != iprh_tmp->start) {
+          /* There is a fragment missing between the current
+           * and the previous fragment */
+          valid = 0;
+        }
+      }
+    }
+    q = iprh_tmp->next_pbuf;
+    iprh_prev = iprh_tmp;
+  }
+
+  /* If q is NULL, then we made it to the end of the list. Determine what to do now */
+  if (q == NULL) {
+    if (iprh_prev != NULL) {
+      /* this is (for now), the fragment with the highest offset:
+       * chain it to the last fragment */
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      iprh_prev->next_pbuf = p;
+      if (iprh_prev->end != iprh->start) {
+        valid = 0;
+      }
+    } else {
+#if IP_REASS_CHECK_OVERLAP
+      LWIP_ASSERT("no previous fragment, this must be the first fragment!",
+        ipr->p == NULL);
+#endif /* IP_REASS_CHECK_OVERLAP */
+      /* this is the first fragment we ever received for this ip datagram */
+      ipr->p = p;
+    }
+  }
+
+  /* Track the current number of pbufs current 'in-flight', in order to limit
+  the number of fragments that may be enqueued at any one time */
+  ip6_reass_pbufcount += clen;
+
+  /* Remember IPv6 header if this is the first fragment. */
+  if (iprh->start == 0) {
+    ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
+  }
+
+  /* If this is the last fragment, calculate total packet length. */
+  if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
+    ipr->datagram_len = iprh->end;
+  }
+
+  /* Additional validity tests: we have received first and last fragment. */
+  iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload;
+  if (iprh_tmp->start != 0) {
+    valid = 0;
+  }
+  if (ipr->datagram_len == 0) {
+    valid = 0;
+  }
+
+  /* Final validity test: no gaps between current and last fragment. */
+  iprh_prev = iprh;
+  q = iprh->next_pbuf;
+  while (q != NULL) {
+    iprh = (struct ip6_reass_helper*)q->payload;
+    if (iprh_prev->end != iprh->start) {
+      valid = 0;
+      break;
+    }
+    iprh_prev = iprh;
+    q = iprh->next_pbuf;
+  }
+
+  if (valid) {
+    /* All fragments have been received */
+
+    /* chain together the pbufs contained within the ip6_reassdata list. */
+    iprh = (struct ip6_reass_helper*) ipr->p->payload;
+    while(iprh != NULL) {
+
+      if (iprh->next_pbuf != NULL) {
+        /* Save next helper struct (will be hidden in next step). */
+        iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload;
+
+        /* hide the fragment header for every succeding fragment */
+        pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN);
+        pbuf_cat(ipr->p, iprh->next_pbuf);
+      }
+      else {
+        iprh_tmp = NULL;
+      }
+
+      iprh = iprh_tmp;
+    }
+
+    /* Adjust datagram length by adding header lengths. */
+    ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr)
+                         + IP6_FRAG_HLEN
+                         - IP6_HLEN ;
+
+    /* Set payload length in ip header. */
+    ipr->iphdr->_plen = htons(ipr->datagram_len);
+
+    /* Get the furst pbuf. */
+    p = ipr->p;
+
+    /* Restore Fragment Header in first pbuf. Mark as "single fragment"
+     * packet. Restore nexth. */
+    frag_hdr = (struct ip6_frag_hdr *) p->payload;
+    frag_hdr->_nexth = ipr->nexth;
+    frag_hdr->reserved = 0;
+    frag_hdr->_fragment_offset = 0;
+    frag_hdr->_identification = 0;
+
+    /* Move pbuf back to IPv6 header. */
+    pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
+
+    /* release the sources allocate for the fragment queue entry */
+    if (reassdatagrams == ipr) {
+      /* it was the first in the list */
+      reassdatagrams = ipr->next;
+    } else {
+      /* it wasn't the first, so it must have a valid 'prev' */
+      LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
+      ipr_prev->next = ipr->next;
+    }
+    memp_free(MEMP_IP6_REASSDATA, ipr);
+
+    /* and adjust the number of pbufs currently queued for reassembly. */
+    ip6_reass_pbufcount -= pbuf_clen(p);
+
+    /* Return the pbuf chain */
+    return p;
+  }
+  /* the datagram is not (yet?) reassembled completely */
+  return NULL;
+
+nullreturn:
+  pbuf_free(p);
+  return NULL;
+}
+
+#endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */
+
+#if LWIP_IPV6 && LWIP_IPV6_FRAG
+
+/** Allocate a new struct pbuf_custom_ref */
+static struct pbuf_custom_ref*
+ip6_frag_alloc_pbuf_custom_ref(void)
+{
+  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
+}
+
+/** Free a struct pbuf_custom_ref */
+static void
+ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
+{
+  LWIP_ASSERT("p != NULL", p != NULL);
+  memp_free(MEMP_FRAG_PBUF, p);
+}
+
+/** Free-callback function to free a 'struct pbuf_custom_ref', called by
+ * pbuf_free. */
+static void
+ip6_frag_free_pbuf_custom(struct pbuf *p)
+{
+  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
+  LWIP_ASSERT("pcr != NULL", pcr != NULL);
+  LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
+  if (pcr->original != NULL) {
+    pbuf_free(pcr->original);
+  }
+  ip6_frag_free_pbuf_custom_ref(pcr);
+}
+
+/**
+ * Fragment an IPv6 datagram if too large for the netif or path MTU.
+ *
+ * Chop the datagram in MTU sized chunks and send them in order
+ * by pointing PBUF_REFs into p
+ *
+ * @param p ipv6 packet to send
+ * @param netif the netif on which to send
+ * @param dest destination ipv6 address to which to send
+ *
+ * @return ERR_OK if sent successfully, err_t otherwise
+ */
+err_t
+ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest)
+{
+  struct ip6_hdr *original_ip6hdr;
+  struct ip6_hdr *ip6hdr;
+  struct ip6_frag_hdr * frag_hdr;
+  struct pbuf *rambuf;
+  struct pbuf *newpbuf;
+  static u32_t identification;
+  u16_t nfb;
+  u16_t left, cop;
+  u16_t mtu;
+  u16_t fragment_offset = 0;
+  u16_t last;
+  u16_t poff = IP6_HLEN;
+  u16_t newpbuflen = 0;
+  u16_t left_to_copy;
+
+  identification++;
+
+  original_ip6hdr = (struct ip6_hdr *)p->payload;
+
+  mtu = nd6_get_destination_mtu(dest, netif);
+
+  /* TODO we assume there are no options in the unfragmentable part (IPv6 header). */
+  left = p->tot_len - IP6_HLEN;
+
+  nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;
+
+  while (left) {
+    last = (left <= nfb);
+
+    /* Fill this fragment */
+    cop = last ? left : nfb;
+
+    /* When not using a static buffer, create a chain of pbufs.
+     * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
+     * but limited to the size of an mtu.
+     */
+    rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
+    if (rambuf == NULL) {
+      IP6_FRAG_STATS_INC(ip6_frag.memerr);
+      return ERR_MEM;
+    }
+    LWIP_ASSERT("this needs a pbuf in one piece!",
+                (p->len >= (IP6_HLEN + IP6_FRAG_HLEN)));
+    SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
+    ip6hdr = (struct ip6_hdr *)rambuf->payload;
+    frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
+
+    /* Can just adjust p directly for needed offset. */
+    p->payload = (u8_t *)p->payload + poff;
+    p->len -= poff;
+    p->tot_len -= poff;
+
+    left_to_copy = cop;
+    while (left_to_copy) {
+      struct pbuf_custom_ref *pcr;
+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
+      /* Is this pbuf already empty? */
+      if (!newpbuflen) {
+        p = p->next;
+        continue;
+      }
+      pcr = ip6_frag_alloc_pbuf_custom_ref();
+      if (pcr == NULL) {
+        pbuf_free(rambuf);
+        IP6_FRAG_STATS_INC(ip6_frag.memerr);
+        return ERR_MEM;
+      }
+      /* Mirror this pbuf, although we might not need all of it. */
+      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
+      if (newpbuf == NULL) {
+        ip6_frag_free_pbuf_custom_ref(pcr);
+        pbuf_free(rambuf);
+        IP6_FRAG_STATS_INC(ip6_frag.memerr);
+        return ERR_MEM;
+      }
+      pbuf_ref(p);
+      pcr->original = p;
+      pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;
+
+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
+       * so that it is removed when pbuf_dechain is later called on rambuf.
+       */
+      pbuf_cat(rambuf, newpbuf);
+      left_to_copy -= newpbuflen;
+      if (left_to_copy) {
+        p = p->next;
+      }
+    }
+    poff = newpbuflen;
+
+    /* Set headers */
+    frag_hdr->_nexth = original_ip6hdr->_nexth;
+    frag_hdr->reserved = 0;
+    frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
+    frag_hdr->_identification = htonl(identification);
+
+    IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
+    IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);
+
+    /* No need for separate header pbuf - we allowed room for it in rambuf
+     * when allocated.
+     */
+    IP6_FRAG_STATS_INC(ip6_frag.xmit);
+    netif->output_ip6(netif, rambuf, dest);
+
+    /* Unfortunately we can't reuse rambuf - the hardware may still be
+     * using the buffer. Instead we free it (and the ensuing chain) and
+     * recreate it next time round the loop. If we're lucky the hardware
+     * will have already sent the packet, the free will really free, and
+     * there will be zero memory penalty.
+     */
+
+    pbuf_free(rambuf);
+    left -= cop;
+    fragment_offset += cop;
+  }
+  return ERR_OK;
+}
+
+#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/mld6.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/mld6.c
new file mode 100644 (file)
index 0000000..9db25ba
--- /dev/null
@@ -0,0 +1,578 @@
+/**
+ * @file
+ *
+ * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
+ * No support for MLDv2.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+/* Based on igmp.c implementation of igmp v2 protocol */
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/mld6.h"
+#include "lwip/icmp6.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+#include "lwip/memp.h"
+#include "lwip/stats.h"
+
+#include <string.h>
+
+
+/*
+ * MLD constants
+ */
+#define MLD6_HL                           1
+#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS  (500)
+
+#define MLD6_GROUP_NON_MEMBER             0
+#define MLD6_GROUP_DELAYING_MEMBER        1
+#define MLD6_GROUP_IDLE_MEMBER            2
+
+
+/* The list of joined groups. */
+static struct mld_group* mld_group_list;
+
+
+/* Forward declarations. */
+static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr);
+static err_t mld6_free_group(struct mld_group *group);
+static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
+static void mld6_send(struct mld_group *group, u8_t type);
+
+
+/**
+ * Stop MLD processing on interface
+ *
+ * @param netif network interface on which stop MLD processing
+ */
+err_t
+mld6_stop(struct netif *netif)
+{
+  struct mld_group *group = mld_group_list;
+  struct mld_group *prev  = NULL;
+  struct mld_group *next;
+
+  /* look for groups joined on this interface further down the list */
+  while (group != NULL) {
+    next = group->next;
+    /* is it a group joined on this interface? */
+    if (group->netif == netif) {
+      /* is it the first group of the list? */
+      if (group == mld_group_list) {
+        mld_group_list = next;
+      }
+      /* is there a "previous" group defined? */
+      if (prev != NULL) {
+        prev->next = next;
+      }
+      /* disable the group at the MAC level */
+      if (netif->mld_mac_filter != NULL) {
+        netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER);
+      }
+      /* free group */
+      memp_free(MEMP_MLD6_GROUP, group);
+    } else {
+      /* change the "previous" */
+      prev = group;
+    }
+    /* move to "next" */
+    group = next;
+  }
+  return ERR_OK;
+}
+
+/**
+ * Report MLD memberships for this interface
+ *
+ * @param netif network interface on which report MLD memberships
+ */
+void
+mld6_report_groups(struct netif *netif)
+{
+  struct mld_group *group = mld_group_list;
+
+  while (group != NULL) {
+    if (group->netif == netif) {
+      mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Search for a group that is joined on a netif
+ *
+ * @param ifp the network interface for which to look
+ * @param addr the group ipv6 address to search for
+ * @return a struct mld_group* if the group has been found,
+ *         NULL if the group wasn't found.
+ */
+struct mld_group *
+mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr)
+{
+  struct mld_group *group = mld_group_list;
+
+  while (group != NULL) {
+    if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) {
+      return group;
+    }
+    group = group->next;
+  }
+
+  return NULL;
+}
+
+
+/**
+ * create a new group
+ *
+ * @param ifp the network interface for which to create
+ * @param addr the new group ipv6
+ * @return a struct mld_group*,
+ *         NULL on memory error.
+ */
+static struct mld_group *
+mld6_new_group(struct netif *ifp, ip6_addr_t *addr)
+{
+  struct mld_group *group;
+
+  group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
+  if (group != NULL) {
+    group->netif              = ifp;
+    ip6_addr_set(&(group->group_address), addr);
+    group->timer              = 0; /* Not running */
+    group->group_state        = MLD6_GROUP_IDLE_MEMBER;
+    group->last_reporter_flag = 0;
+    group->use                = 0;
+    group->next               = mld_group_list;
+
+    mld_group_list = group;
+  }
+
+  return group;
+}
+
+/**
+ * Remove a group in the mld_group_list and free
+ *
+ * @param group the group to remove
+ * @return ERR_OK if group was removed from the list, an err_t otherwise
+ */
+static err_t
+mld6_free_group(struct mld_group *group)
+{
+  err_t err = ERR_OK;
+
+  /* Is it the first group? */
+  if (mld_group_list == group) {
+    mld_group_list = group->next;
+  } else {
+    /* look for group further down the list */
+    struct mld_group *tmpGroup;
+    for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
+      if (tmpGroup->next == group) {
+        tmpGroup->next = group->next;
+        break;
+      }
+    }
+    /* Group not find group */
+    if (tmpGroup == NULL)
+      err = ERR_ARG;
+  }
+  /* free group */
+  memp_free(MEMP_MLD6_GROUP, group);
+
+  return err;
+}
+
+
+/**
+ * Process an input MLD message. Called by icmp6_input.
+ *
+ * @param p the mld packet, p->payload pointing to the icmpv6 header
+ * @param inp the netif on which this packet was received
+ */
+void
+mld6_input(struct pbuf *p, struct netif *inp)
+{
+  struct mld_header * mld_hdr;
+  struct mld_group* group;
+
+  MLD6_STATS_INC(mld6.recv);
+
+  /* Check that mld header fits in packet. */
+  if (p->len < sizeof(struct mld_header)) {
+    /* TODO debug message */
+    pbuf_free(p);
+    MLD6_STATS_INC(mld6.lenerr);
+    MLD6_STATS_INC(mld6.drop);
+    return;
+  }
+
+  mld_hdr = (struct mld_header *)p->payload;
+
+  switch (mld_hdr->type) {
+  case ICMP6_TYPE_MLQ: /* Multicast listener query. */
+  {
+    /* Is it a general query? */
+    if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
+        ip6_addr_isany(&(mld_hdr->multicast_address))) {
+      MLD6_STATS_INC(mld6.rx_general);
+      /* Report all groups, except all nodes group, and if-local groups. */
+      group = mld_group_list;
+      while (group != NULL) {
+        if ((group->netif == inp) &&
+            (!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
+            (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
+          mld6_delayed_report(group, mld_hdr->max_resp_delay);
+        }
+        group = group->next;
+      }
+    }
+    else {
+      /* Have we joined this group?
+       * We use IP6 destination address to have a memory aligned copy.
+       * mld_hdr->multicast_address should be the same. */
+      MLD6_STATS_INC(mld6.rx_group);
+      group = mld6_lookfor_group(inp, ip6_current_dest_addr());
+      if (group != NULL) {
+        /* Schedule a report. */
+        mld6_delayed_report(group, mld_hdr->max_resp_delay);
+      }
+    }
+    break; /* ICMP6_TYPE_MLQ */
+  }
+  case ICMP6_TYPE_MLR: /* Multicast listener report. */
+  {
+    /* Have we joined this group?
+     * We use IP6 destination address to have a memory aligned copy.
+     * mld_hdr->multicast_address should be the same. */
+    MLD6_STATS_INC(mld6.rx_report);
+    group = mld6_lookfor_group(inp, ip6_current_dest_addr());
+    if (group != NULL) {
+      /* If we are waiting to report, cancel it. */
+      if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
+        group->timer = 0; /* stopped */
+        group->group_state = MLD6_GROUP_IDLE_MEMBER;
+        group->last_reporter_flag = 0;
+      }
+    }
+    break; /* ICMP6_TYPE_MLR */
+  }
+  case ICMP6_TYPE_MLD: /* Multicast listener done. */
+  {
+    /* Do nothing, router will query us. */
+    break; /* ICMP6_TYPE_MLD */
+  }
+  default:
+    MLD6_STATS_INC(mld6.proterr);
+    MLD6_STATS_INC(mld6.drop);
+    break;
+  }
+
+  pbuf_free(p);
+}
+
+/**
+ * Join a group on a network interface.
+ *
+ * @param srcaddr ipv6 address of the network interface which should
+ *                join a new group. If IP6_ADDR_ANY, join on all netifs
+ * @param groupaddr the ipv6 address of the group to join
+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
+ */
+err_t
+mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct mld_group  *group;
+  struct netif      *netif;
+  u8_t               match;
+  u8_t               i;
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we join this interface ? */
+    match = 0;
+    if (ip6_addr_isany(srcaddr)) {
+      match = 1;
+    }
+    else {
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
+          match = 1;
+          break;
+        }
+      }
+    }
+    if (match) {
+      /* find group or create a new one if not found */
+      group = mld6_lookfor_group(netif, groupaddr);
+
+      if (group == NULL) {
+        /* Joining a new group. Create a new group entry. */
+        group = mld6_new_group(netif, groupaddr);
+        if (group == NULL) {
+          return ERR_MEM;
+        }
+
+        /* Activate this address on the MAC layer. */
+        if (netif->mld_mac_filter != NULL) {
+          netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER);
+        }
+
+        /* Report our membership. */
+        MLD6_STATS_INC(mld6.tx_report);
+        mld6_send(group, ICMP6_TYPE_MLR);
+        mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
+      }
+
+      /* Increment group use */
+      group->use++;
+      err = ERR_OK;
+    }
+
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+/**
+ * Leave a group on a network interface.
+ *
+ * @param srcaddr ipv6 address of the network interface which should
+ *                leave the group. If IP6_ISANY, leave on all netifs
+ * @param groupaddr the ipv6 address of the group to leave
+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise
+ */
+err_t
+mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
+{
+  err_t              err = ERR_VAL; /* no matching interface */
+  struct mld_group  *group;
+  struct netif      *netif;
+  u8_t               match;
+  u8_t               i;
+
+  /* loop through netif's */
+  netif = netif_list;
+  while (netif != NULL) {
+    /* Should we leave this interface ? */
+    match = 0;
+    if (ip6_addr_isany(srcaddr)) {
+      match = 1;
+    }
+    else {
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
+          match = 1;
+          break;
+        }
+      }
+    }
+    if (match) {
+      /* find group */
+      group = mld6_lookfor_group(netif, groupaddr);
+
+      if (group != NULL) {
+        /* Leave if there is no other use of the group */
+        if (group->use <= 1) {
+          /* If we are the last reporter for this group */
+          if (group->last_reporter_flag) {
+            MLD6_STATS_INC(mld6.tx_leave);
+            mld6_send(group, ICMP6_TYPE_MLD);
+          }
+
+          /* Disable the group at the MAC level */
+          if (netif->mld_mac_filter != NULL) {
+            netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER);
+          }
+
+          /* Free the group */
+          mld6_free_group(group);
+        } else {
+          /* Decrement group use */
+          group->use--;
+        }
+        /* Leave on this interface */
+        err = ERR_OK;
+      }
+    }
+    /* proceed to next network interface */
+    netif = netif->next;
+  }
+
+  return err;
+}
+
+
+/**
+ * Periodic timer for mld processing. Must be called every
+ * MLD6_TMR_INTERVAL milliseconds (100).
+ *
+ * When a delaying member expires, a membership report is sent.
+ */
+void
+mld6_tmr(void)
+{
+  struct mld_group *group = mld_group_list;
+
+  while (group != NULL) {
+    if (group->timer > 0) {
+      group->timer--;
+      if (group->timer == 0) {
+        /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
+        if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
+          MLD6_STATS_INC(mld6.tx_report);
+          mld6_send(group, ICMP6_TYPE_MLR);
+          group->group_state = MLD6_GROUP_IDLE_MEMBER;
+        }
+      }
+    }
+    group = group->next;
+  }
+}
+
+/**
+ * Schedule a delayed membership report for a group
+ *
+ * @param group the mld_group for which "delaying" membership report
+ *              should be sent
+ * @param maxresp the max resp delay provided in the query
+ */
+static void
+mld6_delayed_report(struct mld_group *group, u16_t maxresp)
+{
+  /* Convert maxresp from milliseconds to tmr ticks */
+  maxresp = maxresp / MLD6_TMR_INTERVAL;
+  if (maxresp == 0) {
+    maxresp = 1;
+  }
+
+  /* Randomize maxresp. */
+  maxresp = (LWIP_RAND() % (maxresp - 1)) + 1;
+
+  /* Apply timer value if no report has been scheduled already. */
+  if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) ||
+     ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) &&
+      ((group->timer == 0) || (maxresp < group->timer)))) {
+    group->timer = maxresp;
+    group->group_state = MLD6_GROUP_DELAYING_MEMBER;
+  }
+}
+
+/**
+ * Send a MLD message (report or done).
+ *
+ * An IPv6 hop-by-hop options header with a router alert option
+ * is prepended.
+ *
+ * @param group the group to report or quit
+ * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
+ */
+static void
+mld6_send(struct mld_group *group, u8_t type)
+{
+  struct mld_header * mld_hdr;
+  struct pbuf * p;
+  ip6_addr_t * src_addr;
+
+  /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
+  p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
+  if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) {
+    /* We couldn't allocate a suitable pbuf. drop it. */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+    MLD6_STATS_INC(mld6.memerr);
+    return;
+  }
+
+  /* Move to make room for Hop-by-hop options header. */
+  if (pbuf_header(p, -IP6_HBH_HLEN)) {
+    pbuf_free(p);
+    MLD6_STATS_INC(mld6.lenerr);
+    return;
+  }
+
+  /* Select our source address. */
+  if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) {
+    /* This is a special case, when we are performing duplicate address detection.
+     * We must join the multicast group, but we don't have a valid address yet. */
+    src_addr = IP6_ADDR_ANY;
+  } else {
+    /* Use link-local address as source address. */
+    src_addr = netif_ip6_addr(group->netif, 0);
+  }
+
+  /* MLD message header pointer. */
+  mld_hdr = (struct mld_header *)p->payload;
+
+  /* Set fields. */
+  mld_hdr->type = type;
+  mld_hdr->code = 0;
+  mld_hdr->chksum = 0;
+  mld_hdr->max_resp_delay = 0;
+  mld_hdr->reserved = 0;
+  ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
+
+  mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
+    src_addr, &(group->group_address));
+
+  /* Add hop-by-hop headers options: router alert with MLD value. */
+  ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
+
+  /* Send the packet out. */
+  MLD6_STATS_INC(mld6.xmit);
+  ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
+      MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif);
+  pbuf_free(p);
+}
+
+
+
+#endif /* LWIP_IPV6 */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/nd6.c b/l4/pkg/ankh/lib/lwip/lib/contrib/src/core/ipv6/nd6.c
new file mode 100644 (file)
index 0000000..c7402c6
--- /dev/null
@@ -0,0 +1,1732 @@
+/**
+ * @file
+ *
+ * Neighbor discovery and stateless address autoconfiguration for IPv6.
+ * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
+ * (Address autoconfiguration).
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/nd6.h"
+#include "lwip/pbuf.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#include "lwip/netif.h"
+#include "lwip/icmp6.h"
+#include "lwip/mld6.h"
+#include "lwip/stats.h"
+
+#include <string.h>
+
+
+/* Router tables. */
+struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS];
+struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS];
+struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES];
+struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS];
+
+/* Default values, can be updated by a RA message. */
+u32_t reachable_time = LWIP_ND6_REACHABLE_TIME;
+u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* TODO implement this value in timer */
+
+/* Index for cache entries. */
+static u8_t nd6_cached_neighbor_index;
+static u8_t nd6_cached_destination_index;
+
+/* Multicast address holder. */
+static ip6_addr_t multicast_address;
+
+/* Forward declarations. */
+static s8_t nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr);
+static s8_t nd6_new_neighbor_cache_entry(void);
+static void nd6_free_neighbor_cache_entry(s8_t i);
+static s8_t nd6_find_destination_cache_entry(ip6_addr_t * ip6addr);
+static s8_t nd6_new_destination_cache_entry(void);
+static s8_t nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif);
+static s8_t nd6_get_router(ip6_addr_t * router_addr, struct netif * netif);
+static s8_t nd6_new_router(ip6_addr_t * router_addr, struct netif * netif);
+static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif);
+static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif);
+
+#define ND6_SEND_FLAG_MULTICAST_DEST 0x01
+#define ND6_SEND_FLAG_ALLNODES_DEST 0x02
+static void nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags);
+static void nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags);
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+static void nd6_send_rs(struct netif * netif);
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+
+#if LWIP_ND6_QUEUEING
+static void nd6_free_q(struct nd6_q_entry *q);
+static void nd6_send_q(s8_t i);
+#endif /* LWIP_ND6_QUEUEING */
+
+
+/**
+ * Process an incoming neighbor discovery message
+ *
+ * @param p the nd packet, p->payload pointing to the icmpv6 header
+ * @param inp the netif on which this packet was received
+ */
+void
+nd6_input(struct pbuf *p, struct netif *inp)
+{
+  u8_t msg_type;
+  s8_t i;
+
+  ND6_STATS_INC(nd6.recv);
+
+  msg_type = *((u8_t *)p->payload);
+  switch (msg_type) {
+  case ICMP6_TYPE_NA: /* Neighbor Advertisement. */
+  {
+    struct na_header * na_hdr;
+    struct lladdr_option * lladdr_opt;
+
+    /* Check that na header and link-layer address option fit in packet. */
+    if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) {
+      /* TODO debug message */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.lenerr);
+      ND6_STATS_INC(nd6.drop);
+      return;
+    }
+
+    na_hdr = (struct na_header *)p->payload;
+    lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header));
+
+    /* Unsolicited NA?*/
+    if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
+      /* This is an unsolicited NA.
+       * link-layer changed?
+       * part of DAD mechanism? */
+
+      /* Override ip6_current_dest_addr() so that we have an aligned copy. */
+      ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address));
+
+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
+      /* If the target address matches this netif, it is a DAD response. */
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+        if (ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) {
+          /* We are using a duplicate address. */
+          netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
+
+#if LWIP_IPV6_MLD
+          /* Leave solicited node multicast group. */
+          ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]);
+          mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address);
+#endif /* LWIP_IPV6_MLD */
+
+
+
+
+#if LWIP_IPV6_AUTOCONFIG
+          /* Check to see if this address was autoconfigured. */
+          if (!ip6_addr_islinklocal(ip6_current_dest_addr())) {
+            i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp);
+            if (i >= 0) {
+              /* Mark this prefix as duplicate, so that we don't use it
+               * to generate this address again. */
+              prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE;
+            }
+          }
+#endif /* LWIP_IPV6_AUTOCONFIG */
+
+          pbuf_free(p);
+          return;
+        }
+      }
+#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
+
+      /* This is an unsolicited NA, most likely there was a LLADDR change. */
+      i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr());
+      if (i >= 0) {
+        if (na_hdr->flags & ND6_FLAG_OVERRIDE) {
+          MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+        }
+      }
+    }
+    else {
+      /* This is a solicited NA.
+       * neighbor address resolution response?
+       * neighbor unreachability detection response? */
+
+      /* Override ip6_current_dest_addr() so that we have an aligned copy. */
+      ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address));
+
+      /* Find the cache entry corresponding to this na. */
+      i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr());
+      if (i < 0) {
+        /* We no longer care about this target address. drop it. */
+        pbuf_free(p);
+        return;
+      }
+
+      /* Update cache entry. */
+      neighbor_cache[i].netif = inp;
+      neighbor_cache[i].counter.reachable_time = reachable_time;
+      if ((na_hdr->flags & ND6_FLAG_OVERRIDE) ||
+          (neighbor_cache[i].state == ND6_INCOMPLETE)) {
+        MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+      }
+      neighbor_cache[i].state = ND6_REACHABLE;
+
+#if LWIP_ND6_QUEUEING
+      /* Send queued packets, if any. */
+      if (neighbor_cache[i].q != NULL) {
+        nd6_send_q(i);
+      }
+#endif /* LWIP_ND6_QUEUEING */
+    }
+
+    break; /* ICMP6_TYPE_NA */
+  }
+  case ICMP6_TYPE_NS: /* Neighbor solicitation. */
+  {
+    struct ns_header * ns_hdr;
+    struct lladdr_option * lladdr_opt;
+    u8_t accepted;
+
+    /* Check that ns header fits in packet. */
+    if (p->len < sizeof(struct ns_header)) {
+      /* TODO debug message */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.lenerr);
+      ND6_STATS_INC(nd6.drop);
+      return;
+    }
+
+    ns_hdr = (struct ns_header *)p->payload;
+
+    /* Check if there is a link-layer address provided. Only point to it if in this buffer. */
+    lladdr_opt = NULL;
+    if (p->len >= (sizeof(struct ns_header) + sizeof(struct lladdr_option))) {
+      lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header));
+    }
+
+    /* Check if the target address is configured on the receiving netif. */
+    accepted = 0;
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
+      if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) ||
+           (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) &&
+            ip6_addr_isany(ip6_current_src_addr()))) &&
+          ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) {
+        accepted = 1;
+        break;
+      }
+    }
+
+    /* NS not for us? */
+    if (!accepted) {
+      pbuf_free(p);
+      return;
+    }
+
+    /* Check for ANY address in src (DAD algorithm). */
+    if (ip6_addr_isany(ip6_current_src_addr())) {
+      /* Sender is validating this address. */
+      for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
+        if (ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) {
+          /* Send a NA back so that the sender does not use this address. */
+          nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST);
+          if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) {
+            /* We shouldn't use this address either. */
+            netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID);
+          }
+        }
+      }
+    }
+    else {
+      /* Sender is trying to resolve our address. */
+      /* Verify that they included their own link-layer address. */
+      if (lladdr_opt == NULL) {
+        /* Not a valid message. */
+        pbuf_free(p);
+        ND6_STATS_INC(nd6.proterr);
+        ND6_STATS_INC(nd6.drop);
+        return;
+      }
+
+      i = nd6_find_neighbor_cache_entry(ip6_current_src_addr());
+      if ( i>= 0) {
+        /* We already have a record for the solicitor. */
+        if (neighbor_cache[i].state == ND6_INCOMPLETE) {
+          neighbor_cache[i].netif = inp;
+          MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+
+          /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */
+          neighbor_cache[i].state = ND6_DELAY;
+          neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
+        }
+      }
+      else
+      {
+        /* Add their IPv6 address and link-layer address to neighbor cache.
+         * We will need it at least to send a unicast NA message, but most
+         * likely we will also be communicating with this node soon. */
+        i = nd6_new_neighbor_cache_entry();
+        if (i < 0) {
+          /* We couldn't assign a cache entry for this neighbor.
+           * we won't be able to reply. drop it. */
+          pbuf_free(p);
+          ND6_STATS_INC(nd6.memerr);
+          return;
+        }
+        neighbor_cache[i].netif = inp;
+        MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+        ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr());
+
+        /* Receiving a message does not prove reachability: only in one direction.
+         * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
+        neighbor_cache[i].state = ND6_DELAY;
+        neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
+      }
+
+      /* Override ip6_current_dest_addr() so that we have an aligned copy. */
+      ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address));
+
+      /* Send back a NA for us. Allocate the reply pbuf. */
+      nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE);
+    }
+
+    break; /* ICMP6_TYPE_NS */
+  }
+  case ICMP6_TYPE_RA: /* Router Advertisement. */
+  {
+    struct ra_header * ra_hdr;
+    u8_t * buffer; /* Used to copy options. */
+    u16_t offset;
+
+    /* Check that RA header fits in packet. */
+    if (p->len < sizeof(struct ra_header)) {
+      /* TODO debug message */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.lenerr);
+      ND6_STATS_INC(nd6.drop);
+      return;
+    }
+
+    ra_hdr = (struct ra_header *)p->payload;
+
+    /* If we are sending RS messages, stop. */
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+    if (inp->rs_count > 0) {
+      inp->rs_count = 0;
+    }
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+
+    /* Get the matching default router entry. */
+    i = nd6_get_router(ip6_current_src_addr(), inp);
+    if (i < 0) {
+      /* Create a new router entry. */
+      i = nd6_new_router(ip6_current_src_addr(), inp);
+    }
+
+    if (i < 0) {
+      /* Could not create a new router entry. */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.memerr);
+      return;
+    }
+
+    /* Re-set invalidation timer. */
+    default_router_list[i].invalidation_timer = ra_hdr->router_lifetime;
+
+    /* Re-set default timer values. */
+#if LWIP_ND6_ALLOW_RA_UPDATES
+    if (ra_hdr->retrans_timer > 0) {
+      retrans_timer = ra_hdr->retrans_timer;
+    }
+    if (ra_hdr->reachable_time > 0) {
+      reachable_time = ra_hdr->reachable_time;
+    }
+#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
+
+    /* TODO set default hop limit... */
+    /* ra_hdr->current_hop_limit;*/
+
+    /* Update flags in local entry (incl. preference). */
+    default_router_list[i].flags = ra_hdr->flags;
+
+    /* Offset to options. */
+    offset = sizeof(struct ra_header);
+
+    /* Allocate buffer to copy options (so we can traverse pbufs). */
+    buffer = (u8_t *)mem_malloc(sizeof(struct prefix_option)); /* Size of a prefix option, biggest option. */
+    if (buffer == NULL) {
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.memerr);
+      return;
+    }
+
+    /* Process each option. */
+    while ((p->tot_len - offset) > 0) {
+      pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset);
+      switch (buffer[0]) {
+      case ND6_OPTION_TYPE_SOURCE_LLADDR:
+      {
+        struct lladdr_option * lladdr_opt;
+        lladdr_opt = (struct lladdr_option *)buffer;
+        if ((default_router_list[i].neighbor_entry != NULL) &&
+            (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) {
+          SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len);
+          default_router_list[i].neighbor_entry->state = ND6_REACHABLE;
+          default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time;
+        }
+        break;
+      }
+      case ND6_OPTION_TYPE_MTU:
+      {
+        struct mtu_option * mtu_opt;
+        mtu_opt = (struct mtu_option *)buffer;
+        if (mtu_opt->mtu >= 1280) {
+#if LWIP_ND6_ALLOW_RA_UPDATES
+          inp->mtu = mtu_opt->mtu;
+#endif /* LWIP_ND6_ALLOW_RA_UPDATES */
+        }
+        break;
+      }
+      case ND6_OPTION_TYPE_PREFIX_INFO:
+      {
+        struct prefix_option * prefix_opt;
+        prefix_opt = (struct prefix_option *)buffer;
+
+        if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) {
+          /* Add to on-link prefix list. */
+
+          /* Get a memory-aligned copy of the prefix. */
+          ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix));
+
+          /* find cache entry for this prefix. */
+          i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp);
+          if (i < 0) {
+            /* Create a new cache entry. */
+            i = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp);
+          }
+          if (i >= 0) {
+            prefix_list[i].invalidation_timer = prefix_opt->valid_lifetime;
+
+#if LWIP_IPV6_AUTOCONFIG
+            if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) {
+              /* Mark prefix as autonomous, so that address autoconfiguration can take place.
+               * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/
+              prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS;
+            }
+#endif /* LWIP_IPV6_AUTOCONFIG */
+          }
+        }
+
+        break;
+      }
+      case ND6_OPTION_TYPE_ROUTE_INFO:
+      {
+        struct route_option * route_opt;
+        route_opt = (struct route_option *)buffer;
+
+        /* TODO implement preferred routes. */
+
+        break;
+      }
+      default:
+        /* Unrecognized option, abort. */
+        ND6_STATS_INC(nd6.proterr);
+        break;
+      }
+      offset += 8 * ((u16_t)buffer[1]);
+    }
+
+
+    /* free options buffer. */
+    mem_free(buffer);
+
+    break; /* ICMP6_TYPE_RA */
+  }
+  case ICMP6_TYPE_RD: /* Redirect */
+  {
+    struct redirect_header * redir_hdr;
+    struct lladdr_option * lladdr_opt;
+
+    /* Check that Redir header fits in packet. */
+    if (p->len < sizeof(struct redirect_header)) {
+      /* TODO debug message */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.lenerr);
+      ND6_STATS_INC(nd6.drop);
+      return;
+    }
+
+    redir_hdr = (struct redirect_header *)p->payload;
+
+    lladdr_opt = NULL;
+    if (p->len >= (sizeof(struct redirect_header) + sizeof(struct lladdr_option))) {
+      lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header));
+    }
+
+    /* Copy original destination address to current source address, to have an aligned copy. */
+    ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address));
+
+    /* Find dest address in cache */
+    i = nd6_find_destination_cache_entry(ip6_current_src_addr());
+    if (i < 0) {
+      /* Destination not in cache, drop packet. */
+      pbuf_free(p);
+      return;
+    }
+
+    /* Set the new target address. */
+    ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address));
+
+    /* If Link-layer address of other router is given, try to add to neighbor cache. */
+    if (lladdr_opt != NULL) {
+      if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) {
+        /* Copy target address to current source address, to have an aligned copy. */
+        ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address));
+
+        i = nd6_find_neighbor_cache_entry(ip6_current_src_addr());
+        if (i < 0) {
+          i = nd6_new_neighbor_cache_entry();
+          if (i >= 0) {
+            neighbor_cache[i].netif = inp;
+            MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+            ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr());
+
+            /* Receiving a message does not prove reachability: only in one direction.
+             * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
+            neighbor_cache[i].state = ND6_DELAY;
+            neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
+          }
+        }
+        if (i >= 0) {
+          if (neighbor_cache[i].state == ND6_INCOMPLETE) {
+            MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len);
+            /* Receiving a message does not prove reachability: only in one direction.
+             * Delay probe in case we get confirmation of reachability from upper layer (TCP). */
+            neighbor_cache[i].state = ND6_DELAY;
+            neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
+          }
+        }
+      }
+    }
+    break; /* ICMP6_TYPE_RD */
+  }
+  case ICMP6_TYPE_PTB: /* Packet too big */
+  {
+    struct icmp6_hdr *icmp6hdr; /* Packet too big message */
+    struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */
+
+    /* Check that ICMPv6 header + IPv6 header fit in payload */
+    if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) {
+      /* drop short packets */
+      pbuf_free(p);
+      ND6_STATS_INC(nd6.lenerr);
+      ND6_STATS_INC(nd6.drop);
+      return;
+    }
+
+    icmp6hdr = (struct icmp6_hdr *)p->payload;
+    ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr));
+
+    /* Copy original destination address to current source address, to have an aligned copy. */
+    ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest));
+
+    /* Look for entry in destination cache. */
+    i = nd6_find_destination_cache_entry(ip6_current_src_addr());
+    if (i < 0) {
+      /* Destination not in cache, drop packet. */
+      pbuf_free(p);
+      return;
+    }
+
+    /* Change the Path MTU. */
+    destination_cache[i].pmtu = icmp6hdr->data;
+
+    break; /* ICMP6_TYPE_PTB */
+  }
+
+  default:
+    ND6_STATS_INC(nd6.proterr);
+    ND6_STATS_INC(nd6.drop);
+    break; /* default */
+  }
+
+  pbuf_free(p);
+}
+
+
+/**
+ * Periodic timer for Neighbor discovery functions:
+ *
+ * - Update neighbor reachability states
+ * - Update destination cache entries age
+ * - Update invalidation timers of default routers and on-link prefixes
+ * - Perform duplicate address detection (DAD) for our addresses
+ * - Send router solicitations
+ */
+void
+nd6_tmr(void)
+{
+  s8_t i, j;
+  struct netif * netif;
+
+  /* Process neighbor entries. */
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    switch (neighbor_cache[i].state) {
+    case ND6_INCOMPLETE:
+      if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) {
+        /* Retries exceeded. */
+        nd6_free_neighbor_cache_entry(i);
+      }
+      else {
+        /* Send a NS for this entry. */
+        neighbor_cache[i].counter.probes_sent++;
+        nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST);
+      }
+      break;
+    case ND6_REACHABLE:
+#if LWIP_ND6_QUEUEING
+      /* Send queued packets, if any are left. Should have been sent already. */
+      if (neighbor_cache[i].q != NULL) {
+        nd6_send_q(i);
+      }
+#endif /* LWIP_ND6_QUEUEING */
+      if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) {
+        /* Change to stale state. */
+        neighbor_cache[i].state = ND6_STALE;
+        neighbor_cache[i].counter.stale_time = 0;
+      }
+      else {
+        neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL;
+      }
+      break;
+    case ND6_STALE:
+      neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL;
+      break;
+    case ND6_DELAY:
+      if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) {
+        /* Change to PROBE state. */
+        neighbor_cache[i].state = ND6_PROBE;
+        neighbor_cache[i].counter.probes_sent = 0;
+      }
+      else {
+        neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL;
+      }
+      break;
+    case ND6_PROBE:
+      if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) {
+        /* Retries exceeded. */
+        nd6_free_neighbor_cache_entry(i);
+      }
+      else {
+        /* Send a NS for this entry. */
+        neighbor_cache[i].counter.probes_sent++;
+        nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0);
+      }
+      break;
+    case ND6_NO_ENTRY:
+    default:
+      /* Do nothing. */
+      break;
+    }
+  }
+
+  /* Process destination entries. */
+  for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
+    destination_cache[i].age++;
+  }
+
+  /* Process router entries. */
+  for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
+    if (default_router_list[i].neighbor_entry != NULL) {
+      /* Active entry. */
+      if (default_router_list[i].invalidation_timer > 0) {
+        default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000;
+      }
+      if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) {
+        /* Less than 1 second remainig. Clear this entry. */
+        default_router_list[i].neighbor_entry->isrouter = 0;
+        default_router_list[i].neighbor_entry = NULL;
+        default_router_list[i].invalidation_timer = 0;
+        default_router_list[i].flags = 0;
+      }
+    }
+  }
+
+  /* Process prefix entries. */
+  for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
+    if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) {
+      prefix_list[i].invalidation_timer = 0;
+    }
+    if ((prefix_list[i].invalidation_timer > 0) &&
+        (prefix_list[i].netif != NULL)) {
+      prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000;
+
+#if LWIP_IPV6_AUTOCONFIG
+      /* Initiate address autoconfiguration for this prefix, if conditions are met. */
+      if (prefix_list[i].netif->ip6_autoconfig_enabled &&
+          (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) &&
+          !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) {
+        /* Try to get an address on this netif that is invalid.
+         * Skip 0 index (link-local address) */
+        for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) {
+          if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDRESS_STATE_INVALID) {
+            /* Generate an address using this prefix and interface ID from link-local address. */
+            prefix_list[i].netif->ip6_addr[j].addr[0] = prefix_list[i].prefix.addr[0];
+            prefix_list[i].netif->ip6_addr[j].addr[1] = prefix_list[i].prefix.addr[1];
+            prefix_list[i].netif->ip6_addr[j].addr[2] = prefix_list[i].netif->ip6_addr[0].addr[2];
+            prefix_list[i].netif->ip6_addr[j].addr[3] = prefix_list[i].netif->ip6_addr[0].addr[3];
+
+            /* Mark it as tentative (DAD will be performed if configured). */
+            netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE);
+
+            /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */
+            prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED;
+
+            /* Exit loop. */
+            break;
+          }
+        }
+      }
+#endif /* LWIP_IPV6_AUTOCONFIG */
+    }
+  }
+
+
+  /* Process our own addresses, if DAD configured. */
+  for (netif = netif_list; netif != NULL; netif = netif->next) {
+    for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
+      if (ip6_addr_istentative(netif->ip6_addr_state[i])) {
+        if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
+          /* No NA received in response. Mark address as valid. */
+          netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED;
+          /* TODO implement preferred and valid lifetimes. */
+        }
+        else if (netif->flags & NETIF_FLAG_UP) {
+#if LWIP_IPV6_MLD
+          if ((netif->ip6_addr_state[i] & 0x07) == 0) {
+            /* Join solicited node multicast group. */
+            ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]);
+            mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address);
+          }
+#endif /* LWIP_IPV6_MLD */
+          /* Send a NS for this address. */
+          nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST);
+          (netif->ip6_addr_state[i])++;
+          /* TODO send max 1 NS per tmr call? enable return*/
+          /*return;*/
+        }
+      }
+    }
+  }
+
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+  /* Send router solicitation messages, if necessary. */
+  for (netif = netif_list; netif != NULL; netif = netif->next) {
+    if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP)) {
+      nd6_send_rs(netif);
+      netif->rs_count--;
+    }
+  }
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+
+}
+
+/**
+ * Send a neighbor solicitation message
+ *
+ * @param netif the netif on which to send the message
+ * @param target_addr the IPv6 target address for the ND message
+ * @param flags one of ND6_SEND_FLAG_*
+ */
+static void
+nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags)
+{
+  struct ns_header * ns_hdr;
+  struct lladdr_option * lladdr_opt;
+  struct pbuf * p;
+  ip6_addr_t * src_addr;
+
+  if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) {
+    /* Use link-local address as source address. */
+    src_addr = netif_ip6_addr(netif, 0);
+  } else {
+    src_addr = IP6_ADDR_ANY;
+  }
+
+  /* Allocate a packet. */
+  p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + sizeof(struct lladdr_option), PBUF_RAM);
+  if ((p == NULL) || (p->len < (sizeof(struct ns_header) + sizeof(struct lladdr_option)))) {
+    /* We couldn't allocate a suitable pbuf for the ns. drop it. */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+    ND6_STATS_INC(nd6.memerr);
+    return;
+  }
+
+  /* Set fields. */
+  ns_hdr = (struct ns_header *)p->payload;
+  lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header));
+
+  ns_hdr->type = ICMP6_TYPE_NS;
+  ns_hdr->code = 0;
+  ns_hdr->chksum = 0;
+  ns_hdr->reserved = 0;
+  ip6_addr_set(&(ns_hdr->target_address), target_addr);
+
+  lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR;
+  lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0);
+  SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
+
+  /* Generate the solicited node address for the target address. */
+  if (flags & ND6_SEND_FLAG_MULTICAST_DEST) {
+    ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]);
+    target_addr = &multicast_address;
+  }
+
+  ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
+    target_addr);
+
+  /* Send the packet out. */
+  ND6_STATS_INC(nd6.xmit);
+  ip6_output_if(p, (src_addr == IP6_ADDR_ANY) ? NULL : src_addr, target_addr,
+      LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
+  pbuf_free(p);
+}
+
+/**
+ * Send a neighbor advertisement message
+ *
+ * @param netif the netif on which to send the message
+ * @param target_addr the IPv6 target address for the ND message
+ * @param flags one of ND6_SEND_FLAG_*
+ */
+static void
+nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags)
+{
+  struct na_header * na_hdr;
+  struct lladdr_option * lladdr_opt;
+  struct pbuf * p;
+  ip6_addr_t * src_addr;
+  ip6_addr_t * dest_addr;
+
+  /* Use link-local address as source address. */
+  /* src_addr = &(netif->ip6_addr[0]); */
+  /* Use target address as source address. */
+  src_addr = target_addr;
+
+  /* Allocate a packet. */
+  p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + sizeof(struct lladdr_option), PBUF_RAM);
+  if ((p == NULL) || (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option)))) {
+    /* We couldn't allocate a suitable pbuf for the ns. drop it. */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+    ND6_STATS_INC(nd6.memerr);
+    return;
+  }
+
+  /* Set fields. */
+  na_hdr = (struct na_header *)p->payload;
+  lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header));
+
+  na_hdr->type = ICMP6_TYPE_NA;
+  na_hdr->code = 0;
+  na_hdr->chksum = 0;
+  na_hdr->flags = flags & 0xf0;
+  na_hdr->reserved[0] = 0;
+  na_hdr->reserved[1] = 0;
+  na_hdr->reserved[2] = 0;
+  ip6_addr_set(&(na_hdr->target_address), target_addr);
+
+  lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR;
+  lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0);
+  SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
+
+  /* Generate the solicited node address for the target address. */
+  if (flags & ND6_SEND_FLAG_MULTICAST_DEST) {
+    ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]);
+    dest_addr = &multicast_address;
+  }
+  else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) {
+    ip6_addr_set_allnodes_linklocal(&multicast_address);
+    dest_addr = &multicast_address;
+  }
+  else {
+    dest_addr = ip6_current_src_addr();
+  }
+
+  na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
+    dest_addr);
+
+  /* Send the packet out. */
+  ND6_STATS_INC(nd6.xmit);
+  ip6_output_if(p, src_addr, dest_addr,
+      LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
+  pbuf_free(p);
+}
+
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+/**
+ * Send a router solicitation message
+ *
+ * @param netif the netif on which to send the message
+ */
+static void
+nd6_send_rs(struct netif * netif)
+{
+  struct rs_header * rs_hdr;
+  struct lladdr_option * lladdr_opt;
+  struct pbuf * p;
+  ip6_addr_t * src_addr;
+  u16_t packet_len;
+
+  /* Link-local source address, or unspecified address? */
+  if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) {
+    src_addr = netif_ip6_addr(netif, 0);
+  }
+  else {
+    src_addr = IP6_ADDR_ANY;
+  }
+
+  /* Generate the all routers target address. */
+  ip6_addr_set_allrouters_linklocal(&multicast_address);
+
+  /* Allocate a packet. */
+  packet_len = sizeof(struct rs_header);
+  if (src_addr != IP6_ADDR_ANY) {
+    packet_len += sizeof(struct lladdr_option);
+  }
+  p = pbuf_alloc(PBUF_IP, packet_len, PBUF_RAM);
+  if ((p == NULL) || (p->len < packet_len)) {
+    /* We couldn't allocate a suitable pbuf for the ns. drop it. */
+    if (p != NULL) {
+      pbuf_free(p);
+    }
+    ND6_STATS_INC(nd6.memerr);
+    return;
+  }
+
+  /* Set fields. */
+  rs_hdr = (struct rs_header *)p->payload;
+
+  rs_hdr->type = ICMP6_TYPE_RS;
+  rs_hdr->code = 0;
+  rs_hdr->chksum = 0;
+  rs_hdr->reserved = 0;
+
+  if (src_addr != IP6_ADDR_ANY) {
+    /* Include our hw address. */
+    lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header));
+    lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR;
+    lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0);
+    SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len);
+  }
+
+  rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr,
+    &multicast_address);
+
+  /* Send the packet out. */
+  ND6_STATS_INC(nd6.xmit);
+  ip6_output_if(p, src_addr, &multicast_address,
+      LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
+  pbuf_free(p);
+}
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+
+/**
+ * Search for a neighbor cache entry
+ *
+ * @param ip6addr the IPv6 address of the neighbor
+ * @return The neighbor cache entry index that matched, -1 if no
+ * entry is found
+ */
+static s8_t
+nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr)
+{
+  s8_t i;
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+/**
+ * Create a new neighbor cache entry.
+ *
+ * If no unused entry is found, will try to recycle an old entry
+ * according to ad-hoc "age" heuristic.
+ *
+ * @return The neighbor cache entry index that was created, -1 if no
+ * entry could be created
+ */
+static s8_t
+nd6_new_neighbor_cache_entry(void)
+{
+  s8_t i;
+  s8_t j;
+  u32_t time;
+
+
+  /* First, try to find an empty entry. */
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if (neighbor_cache[i].state == ND6_NO_ENTRY) {
+      return i;
+    }
+  }
+
+  /* We need to recycle an entry. in general, do not recycle if it is a router. */
+
+  /* Next, try to find a Stale entry. */
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if ((neighbor_cache[i].state == ND6_STALE) &&
+        (!neighbor_cache[i].isrouter)) {
+      nd6_free_neighbor_cache_entry(i);
+      return i;
+    }
+  }
+
+  /* Next, try to find a Probe entry. */
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if ((neighbor_cache[i].state == ND6_PROBE) &&
+        (!neighbor_cache[i].isrouter)) {
+      nd6_free_neighbor_cache_entry(i);
+      return i;
+    }
+  }
+
+  /* Next, try to find a Delayed entry. */
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if ((neighbor_cache[i].state == ND6_DELAY) &&
+        (!neighbor_cache[i].isrouter)) {
+      nd6_free_neighbor_cache_entry(i);
+      return i;
+    }
+  }
+
+  /* Next, try to find the oldest reachable entry. */
+  time = 0xfffffffful;
+  j = -1;
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if ((neighbor_cache[i].state == ND6_REACHABLE) &&
+        (!neighbor_cache[i].isrouter)) {
+      if (neighbor_cache[i].counter.reachable_time < time) {
+        j = i;
+        time = neighbor_cache[i].counter.reachable_time;
+      }
+    }
+  }
+  if (j >= 0) {
+    nd6_free_neighbor_cache_entry(j);
+    return j;
+  }
+
+  /* Next, find oldest incomplete entry without queued packets. */
+  time = 0;
+  j = -1;
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if (
+#if LWIP_ND6_QUEUEING
+        (neighbor_cache[i].q == NULL) &&
+#endif /* LWIP_ND6_QUEUEING */
+        (neighbor_cache[i].state == ND6_INCOMPLETE) &&
+        (!neighbor_cache[i].isrouter)) {
+      if (neighbor_cache[i].counter.probes_sent >= time) {
+        j = i;
+        time = neighbor_cache[i].counter.probes_sent;
+      }
+    }
+  }
+  if (j >= 0) {
+    nd6_free_neighbor_cache_entry(j);
+    return j;
+  }
+
+  /* Next, find oldest incomplete entry with queued packets. */
+#if LWIP_ND6_QUEUEING
+  time = 0;
+  j = -1;
+  for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) {
+    if ((neighbor_cache[i].state == ND6_INCOMPLETE) &&
+        (!neighbor_cache[i].isrouter)) {
+      if (neighbor_cache[i].counter.probes_sent >= time) {
+        j = i;
+        time = neighbor_cache[i].counter.probes_sent;
+      }
+    }
+  }
+  if (j >= 0) {
+    nd6_free_neighbor_cache_entry(j);
+    return j;
+  }
+#endif /* LWIP_ND6_QUEUEING */
+
+  /* No more entries to try. */
+  return -1;
+}
+
+/**
+ * Will free any resources associated with a neighbor cache
+ * entry, and will mark it as unused.
+ *
+ * @param i the neighbor cache entry index to free
+ */
+static void
+nd6_free_neighbor_cache_entry(s8_t i)
+{
+#if LWIP_ND6_QUEUEING
+  /* Free any queued packets. */
+  if (neighbor_cache[i].q != NULL) {
+    nd6_free_q(neighbor_cache[i].q);
+    neighbor_cache[i].q = NULL;
+  }
+#endif /* LWIP_ND6_QUEUEING */
+
+  neighbor_cache[i].state = ND6_NO_ENTRY;
+  neighbor_cache[i].isrouter = 0;
+  neighbor_cache[i].netif = NULL;
+  neighbor_cache[i].counter.reachable_time = 0;
+  ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address));
+}
+
+/**
+ * Search for a destination cache entry
+ *
+ * @param ip6addr the IPv6 address of the destination
+ * @return The destination cache entry index that matched, -1 if no
+ * entry is found
+ */
+static s8_t
+nd6_find_destination_cache_entry(ip6_addr_t * ip6addr)
+{
+  s8_t i;
+  for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
+    if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+/**
+ * Create a new destination cache entry. If no unused entry is found,
+ * will recycle oldest entry.
+ *
+ * @return The destination cache entry index that was created, -1 if no
+ * entry was created
+ */
+static s8_t
+nd6_new_destination_cache_entry(void)
+{
+  s8_t i, j;
+  u32_t age;
+
+  /* Find an empty entry. */
+  for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
+    if (ip6_addr_isany(&(destination_cache[i].destination_addr))) {
+      return i;
+    }
+  }
+
+  /* Find oldest entry. */
+  age = 0;
+  j = LWIP_ND6_NUM_DESTINATIONS - 1;
+  for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) {
+    if (destination_cache[i].age > age) {
+      j = i;
+    }
+  }
+
+  return j;
+}
+
+/**
+ * Determine whether an address matches an on-link prefix.
+ *
+ * @param ip6addr the IPv6 address to match
+ * @return 1 if the address is on-link, 0 otherwise
+ */
+static s8_t
+nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif)
+{
+  s8_t i;
+  for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
+    if ((prefix_list[i].netif == netif) &&
+        (prefix_list[i].invalidation_timer > 0) &&
+        ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) {
+      return 1;
+    }
+  }
+  /* Check to see if address prefix matches a (manually?) configured address. */
+  for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+    if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
+        ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/**
+ * Select a default router for a destination.
+ *
+ * @param ip6addr the destination address
+ * @param netif the netif for the outgoing packet, if known
+ * @return the default router entry index, or -1 if no suitable
+ *         router is found
+ */
+s8_t
+nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif)
+{
+  s8_t i;
+  /* last_router is used for round-robin router selection (as recommended
+   * in RFC). This is more robust in case one router is not reachable,
+   * we are not stuck trying to resolve it. */
+  static s8_t last_router;
+  (void)ip6addr; /* TODO match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */
+
+  /* TODO: implement default router preference */
+
+  /* Look for reachable routers. */
+  for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
+    if (++last_router >= LWIP_ND6_NUM_ROUTERS) {
+      last_router = 0;
+    }
+    if ((default_router_list[i].neighbor_entry != NULL) &&
+        (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) &&
+        (default_router_list[i].invalidation_timer > 0) &&
+        (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) {
+      return i;
+    }
+  }
+
+  /* Look for router in other reachability states, but still valid according to timer. */
+  for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
+    if (++last_router >= LWIP_ND6_NUM_ROUTERS) {
+      last_router = 0;
+    }
+    if ((default_router_list[i].neighbor_entry != NULL) &&
+        (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) &&
+        (default_router_list[i].invalidation_timer > 0)) {
+      return i;
+    }
+  }
+
+  /* Look for any router for which we have any information at all. */
+  for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
+    if (++last_router >= LWIP_ND6_NUM_ROUTERS) {
+      last_router = 0;
+    }
+    if (default_router_list[i].neighbor_entry != NULL &&
+        (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) {
+      return i;
+    }
+  }
+
+  /* no suitable router found. */
+  return -1;
+}
+
+/**
+ * Find an entry for a default router.
+ *
+ * @param router_addr the IPv6 address of the router
+ * @param netif the netif on which the router is found, if known
+ * @return the index of the router entry, or -1 if not found
+ */
+static s8_t
+nd6_get_router(ip6_addr_t * router_addr, struct netif * netif)
+{
+  s8_t i;
+
+  /* Look for router. */
+  for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) {
+    if ((default_router_list[i].neighbor_entry != NULL) &&
+        ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) &&
+        ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) {
+      return i;
+    }
+  }
+
+  /* router not found. */
+  return -1;
+}
+
+/**
+ * Create a new entry for a default router.
+ *
+ * @param router_addr the IPv6 address of the router
+ * @param netif the netif on which the router is connected, if known
+ * @return the index on the router table, or -1 if could not be created
+ */
+static s8_t
+nd6_new_router(ip6_addr_t * router_addr, struct netif * netif)
+{
+  s8_t router_index;
+  s8_t neighbor_index;
+
+  /* Do we have a neighbor entry for this router? */
+  neighbor_index = nd6_find_neighbor_cache_entry(router_addr);
+  if (neighbor_index < 0) {
+    /* Create a neighbor entry for this router. */
+    neighbor_index = nd6_new_neighbor_cache_entry();
+    if (neighbor_index < 0) {
+      /* Could not create neighbor entry for this router. */
+      return -1;
+    }
+    ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr);
+    neighbor_cache[neighbor_index].netif = netif;
+    neighbor_cache[neighbor_index].q = NULL;
+    neighbor_cache[neighbor_index].state = ND6_INCOMPLETE;
+    neighbor_cache[neighbor_index].counter.probes_sent = 0;
+  }
+
+  /* Mark neighbor as router. */
+  neighbor_cache[neighbor_index].isrouter = 1;
+
+  /* Look for empty entry. */
+  for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) {
+    if (default_router_list[router_index].neighbor_entry == NULL) {
+      default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]);
+      return router_index;
+    }
+  }
+
+  /* Could not create a router entry. */
+
+  /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */
+  neighbor_cache[neighbor_index].isrouter = 0;
+
+  /* router not found. */
+  return -1;
+}
+
+/**
+ * Find the cached entry for an on-link prefix.
+ *
+ * @param prefix the IPv6 prefix that is on-link
+ * @param netif the netif on which the prefix is on-link
+ * @return the index on the prefix table, or -1 if not found
+ */
+static s8_t
+nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
+{
+  s8_t i;
+
+  /* Look for prefix in list. */
+  for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
+    if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) &&
+        (prefix_list[i].netif == netif)) {
+      return i;
+    }
+  }
+
+  /* Entry not available. */
+  return -1;
+}
+
+/**
+ * Creates a new entry for an on-link prefix.
+ *
+ * @param prefix the IPv6 prefix that is on-link
+ * @param netif the netif on which the prefix is on-link
+ * @return the index on the prefix table, or -1 if not created
+ */
+static s8_t
+nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif)
+{
+  s8_t i;
+
+  /* Create new entry. */
+  for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
+    if ((prefix_list[i].netif == NULL) ||
+        (prefix_list[i].invalidation_timer == 0)) {
+      /* Found empty prefix entry. */
+      prefix_list[i].netif = netif;
+      ip6_addr_set(&(prefix_list[i].prefix), prefix);
+      prefix_list[i].flags = 0;
+      return i;
+    }
+  }
+
+  /* Entry not available. */
+  return -1;
+}
+
+/**
+ * Determine the next hop for a destination. Will determine if the
+ * destination is on-link, else a suitable on-link router is selected.
+ *
+ * The last entry index is cached for fast entry search.
+ *
+ * @param ip6addr the destination address
+ * @param netif the netif on which the packet will be sent
+ * @return the neighbor cache entry for the next hop, ERR_RTE if no
+ *         suitable next hop was found, ERR_MEM if no cache entry
+ *         could be created
+ */
+s8_t
+nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif)
+{
+  s8_t i;
+
+#if LWIP_NETIF_HWADDRHINT
+  if (netif->addr_hint != NULL) {
+    /* per-pcb cached entry was given */
+    u8_t addr_hint = *(netif->addr_hint);
+    if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) {
+      nd6_cached_destination_index = addr_hint;
+    }
+  }
+#endif /* LWIP_NETIF_HWADDRHINT */
+
+  /* Look for ip6addr in destination cache. */
+  if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) {
+    /* the cached entry index is the right one! */
+    /* do nothing. */
+    ND6_STATS_INC(nd6.cachehit);
+  } else {
+    /* Search destination cache. */
+    i = nd6_find_destination_cache_entry(ip6addr);
+    if (i >= 0) {
+      /* found destination entry. make it our new cached index. */
+      nd6_cached_destination_index = i;
+    }
+    else {
+      /* Not found. Create a new destination entry. */
+      i = nd6_new_destination_cache_entry();
+      if (i >= 0) {
+        /* got new destination entry. make it our new cached index. */
+        nd6_cached_destination_index = i;
+      } else {
+        /* Could not create a destination cache entry. */
+        return ERR_MEM;
+      }
+
+      /* Copy dest address to destination cache. */
+      ip6_addr_set(&(destination_cache[i].destination_addr), ip6addr);
+
+      /* Now find the next hop. is it a neighbor? */
+      if (ip6_addr_islinklocal(ip6addr) ||
+          nd6_is_prefix_in_netif(ip6addr, netif)) {
+        /* Destination in local link. */
+        destination_cache[i].pmtu = netif->mtu;
+        ip6_addr_copy(destination_cache[i].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr);
+      }
+      else {
+        /* We need to select a router. */
+        i = nd6_select_router(ip6addr, netif);
+        if (i < 0) {
+          /* No router found. */
+          ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr));
+          return ERR_RTE;
+        }
+        destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */
+        ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address);
+      }
+    }
+  }
+
+#if LWIP_NETIF_HWADDRHINT
+  if (netif->addr_hint != NULL) {
+    /* per-pcb cached entry was given */
+    *(netif->addr_hint) = nd6_cached_destination_index;
+  }
+#endif /* LWIP_NETIF_HWADDRHINT */
+
+  /* Look in neighbor cache for the next-hop address. */
+  if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr),
+                   &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) {
+    /* Cache hit. */
+    /* Do nothing. */
+    ND6_STATS_INC(nd6.cachehit);
+  } else {
+    i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr));
+    if (i >= 0) {
+      /* Found a matching record, make it new cached entry. */
+      nd6_cached_neighbor_index = i;
+    }
+    else {
+      /* Neighbor not in cache. Make a new entry. */
+      i = nd6_new_neighbor_cache_entry();
+      if (i >= 0) {
+        /* got new neighbor entry. make it our new cached index. */
+        nd6_cached_neighbor_index = i;
+      } else {
+        /* Could not create a neighbor cache entry. */
+        return ERR_MEM;
+      }
+
+      /* Initialize fields. */
+      ip6_addr_copy(neighbor_cache[i].next_hop_address,
+                   destination_cache[nd6_cached_destination_index].next_hop_addr);
+      neighbor_cache[i].isrouter = 0;
+      neighbor_cache[i].netif = netif;
+      neighbor_cache[i].state = ND6_INCOMPLETE;
+      neighbor_cache[i].counter.probes_sent = 0;
+    }
+  }
+
+  /* Reset this destination's age. */
+  destination_cache[nd6_cached_destination_index].age = 0;
+
+  return nd6_cached_neighbor_index;
+}
+
+#if LWIP_ND6_QUEUEING
+
+/**
+ * Queue a packet for a neighbor.
+ *
+ * @param neighbor_index the index in the neighbor cache table
+ * @param q packet to be queued
+ * @return ERR_OK if succeeded, ERR_MEM if out of memory
+ */
+err_t
+nd6_queue_packet(s8_t neighbor_index, struct pbuf * q)
+{
+  err_t result = ERR_MEM;
+  struct pbuf *p;
+  int copy_needed = 0;
+  struct nd6_q_entry *new_entry, *r;
+
+  /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
+   * to copy the whole queue into a new PBUF_RAM (see bug #11400)
+   * PBUF_ROMs can be left as they are, since ROM must not get changed. */
+  p = q;
+  while (p) {
+    if(p->type != PBUF_ROM) {
+      copy_needed = 1;
+      break;
+    }
+    p = p->next;
+  }
+  if(copy_needed) {
+    /* copy the whole packet into new pbufs */
+    p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM);
+    if ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
+      /* Free oldest packet (as per RFC recommendation) */
+      r = neighbor_cache[neighbor_index].q;
+      neighbor_cache[neighbor_index].q = r->next;
+      nd6_free_q(r);
+      p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM);
+    }
+    if(p != NULL) {
+      if (pbuf_copy(p, q) != ERR_OK) {
+        pbuf_free(p);
+        p = NULL;
+      }
+    }
+  } else {
+    /* referencing the old pbuf is enough */
+    p = q;
+    pbuf_ref(p);
+  }
+  /* packet was copied/ref'd? */
+  if (p != NULL) {
+    /* queue packet ... */
+    /* allocate a new nd6 queue entry */
+    new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE);
+    if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) {
+      /* Free oldest packet (as per RFC recommendation) */
+      r = neighbor_cache[neighbor_index].q;
+      neighbor_cache[neighbor_index].q = r->next;
+      nd6_free_q(r);
+      new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE);
+    }
+    if (new_entry != NULL) {
+      new_entry->next = NULL;
+      new_entry->p = p;
+      if(neighbor_cache[neighbor_index].q != NULL) {
+        /* queue was already existent, append the new entry to the end */
+        r = neighbor_cache[neighbor_index].q;
+        while (r->next != NULL) {
+          r = r->next;
+        }
+        r->next = new_entry;
+      } else {
+        /* queue did not exist, first item in queue */
+        neighbor_cache[neighbor_index].q = new_entry;
+      }
+      LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)q, (s16_t)neighbor_index));
+      result = ERR_OK;
+    } else {
+      /* the pool MEMP_ND6_QUEUE is empty */
+      pbuf_free(p);
+      LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q));
+      /* { result == ERR_MEM } through initialization */
+    }
+  } else {
+    LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q));
+    /* { result == ERR_MEM } through initialization */
+  }
+
+  return result;
+}
+
+/**
+ * Free a complete queue of nd6 q entries
+ *
+ * @param q a queue of nd6_q_entry to free
+ */
+static void
+nd6_free_q(struct nd6_q_entry *q)
+{
+  struct nd6_q_entry *r;
+  LWIP_ASSERT("q != NULL", q != NULL);
+  LWIP_ASSERT("q->p != NULL", q->p != NULL);
+  while (q) {
+    r = q;
+    q = q->next;
+    LWIP_ASSERT("r->p != NULL", (r->p != NULL));
+    pbuf_free(r->p);
+    memp_free(MEMP_ND6_QUEUE, r);
+  }
+}
+
+/**
+ * Send queued packets for a neighbor
+ *
+ * @param i the neighbor to send packets to
+ */
+static void
+nd6_send_q(s8_t i)
+{
+  struct ip6_hdr *ip6hdr;
+  struct nd6_q_entry *q;
+
+  while (neighbor_cache[i].q != NULL) {
+    /* remember first in queue */
+    q = neighbor_cache[i].q;
+    /* pop first item off the queue */
+    neighbor_cache[i].q = q->next;
+    /* Get ipv6 header. */
+    ip6hdr = (struct ip6_hdr *)(q->p->payload);
+    /* Override ip6_current_dest_addr() so that we have an aligned copy. */
+    ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest));
+    /* send the queued IPv6 packet */
+    (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr());
+    /* free the queued IP packet */
+    pbuf_free(q->p);
+    /* now queue entry can be freed */
+    memp_free(MEMP_ND6_QUEUE, q);
+  }
+}
+
+#endif /* LWIP_ND6_QUEUEING */
+
+/**
+ * Get the Path MTU for a destination.
+ *
+ * @param ip6addr the destination address
+ * @param netif the netif on which the packet will be sent
+ * @return the Path MTU, if known, or the netif default MTU
+ */
+u16_t
+nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif)
+{
+  s8_t i;
+
+  i = nd6_find_destination_cache_entry(ip6addr);
+  if (i >= 0) {
+    if (destination_cache[i].pmtu > 0) {
+      return destination_cache[i].pmtu;
+    }
+  }
+
+  if (netif != NULL) {
+    return netif->mtu;
+  }
+
+  return 1280; /* Minimum MTU */
+}
+
+
+#if LWIP_ND6_TCP_REACHABILITY_HINTS
+/**
+ * Provide the Neighbor discovery process with a hint that a
+ * destination is reachable. Called by tcp_receive when ACKs are
+ * received or sent (as per RFC). This is useful to avoid sending
+ * NS messages every 30 seconds.
+ *
+ * @param ip6addr the destination address which is know to be reachable
+ *                by an upper layer protocol (TCP)
+ */
+void
+nd6_reachability_hint(ip6_addr_t * ip6addr)
+{
+  s8_t i;
+
+  /* Find destination in cache. */
+  if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) {
+    i = nd6_cached_destination_index;
+    ND6_STATS_INC(nd6.cachehit);
+  }
+  else {
+    i = nd6_find_destination_cache_entry(ip6addr);
+  }
+  if (i < 0) {
+    return;
+  }
+
+  /* Find next hop neighbor in cache. */
+  if (ip6_addr_cmp(&(destination_cache[i].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) {
+    i = nd6_cached_neighbor_index;
+    ND6_STATS_INC(nd6.cachehit);
+  }
+  else {
+    i = nd6_find_neighbor_cache_entry(&(destination_cache[i].next_hop_addr));
+  }
+  if (i < 0) {
+    return;
+  }
+
+  /* Set reachability state. */
+  neighbor_cache[i].state = ND6_REACHABLE;
+  neighbor_cache[i].counter.reachable_time = reachable_time;
+}
+#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
+
+#endif /* LWIP_IPV6 */
index 98375553b9e8ece3378b78a89f75013e1b58f279..2128a28e32c889ae8c8c29003aeaea29d35f53b5 100644 (file)
 void *
 mem_malloc(mem_size_t size)
 {
+  void *ret;
   struct memp_malloc_helper *element;
   memp_t poolnr;
-  mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
+  mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
 
   for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
 #if MEM_USE_POOLS_TRY_BIGGER_POOL
@@ -113,9 +114,9 @@ again:
   /* save the pool number this element came from */
   element->poolnr = poolnr;
   /* and return a pointer to the memory directly after the struct memp_malloc_helper */
-  element++;
+  ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
 
-  return element;
+  return ret;
 }
 
 /**
@@ -128,13 +129,13 @@ again:
 void
 mem_free(void *rmem)
 {
-  struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
+  struct memp_malloc_helper *hmem;
 
   LWIP_ASSERT("rmem != NULL", (rmem != NULL));
   LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
 
   /* get the original struct memp_malloc_helper */
-  hmem--;
+  hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
 
   LWIP_ASSERT("hmem != NULL", (hmem != NULL));
   LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
@@ -190,7 +191,9 @@ static struct mem *ram_end;
 static struct mem *lfree;
 
 /** concurrent access protection */
+#if !NO_SYS
 static sys_mutex_t mem_mutex;
+#endif
 
 #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
 
index 4da879a57b46766b499ea70c1f8342302219a417..bfe6ee60568e1a67bef5fc1b3fbb39eeb45e11a7 100644 (file)
@@ -58,6 +58,9 @@
 #include "lwip/snmp_msg.h"
 #include "lwip/dns.h"
 #include "netif/ppp_oe.h"
+#include "lwip/nd6.h"
+#include "lwip/ip6_frag.h"
+#include "lwip/mld6.h"
 
 #include <string.h>
 
index 46530651a1e1a23bf54aef928c430f25567e69a7..754f1112ea42871f24c5fe5c41912f5379d1ed40 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "lwip/def.h"
 #include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
 #include "lwip/netif.h"
 #include "lwip/tcp_impl.h"
 #include "lwip/snmp.h"
 #if LWIP_DHCP
 #include "lwip/dhcp.h"
 #endif /* LWIP_DHCP */
+#if LWIP_IPV6_DHCP6
+#include "lwip/dhcp6.h"
+#endif /* LWIP_IPV6_DHCP6 */
+#if LWIP_IPV6_MLD
+#include "lwip/mld6.h"
+#endif /* LWIP_IPV6_MLD */
 
 #if LWIP_NETIF_STATUS_CALLBACK
 #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
@@ -75,6 +82,8 @@
 struct netif *netif_list;
 struct netif *netif_default;
 
+static u8_t netif_num;
+
 #if LWIP_HAVE_LOOPIF
 static struct netif loop_netif;
 
@@ -137,7 +146,9 @@ struct netif *
 netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
   ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
 {
-  static u8_t netifnum = 0;
+#if LWIP_IPV6
+  u32_t i;
+#endif
 
   LWIP_ASSERT("No init function given", init != NULL);
 
@@ -145,6 +156,12 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
   ip_addr_set_zero(&netif->ip_addr);
   ip_addr_set_zero(&netif->netmask);
   ip_addr_set_zero(&netif->gw);
+#if LWIP_IPV6
+  for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+    ip6_addr_set_zero(&netif->ip6_addr[i]);
+    netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
+  }
+#endif /* LWIP_IPV6 */
   netif->flags = 0;
 #if LWIP_DHCP
   /* netif not under DHCP control by default */
@@ -154,6 +171,17 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
   /* netif not under AutoIP control by default */
   netif->autoip = NULL;
 #endif /* LWIP_AUTOIP */
+#if LWIP_IPV6_AUTOCONFIG
+  /* IPv6 address autoconfiguration not enabled by default */
+  netif->ip6_autoconfig_enabled = 0;
+#endif /* LWIP_IPV6_AUTOCONFIG */
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+  netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+#if LWIP_IPV6_DHCP6
+  /* netif not under DHCPv6 control by default */
+  netif->dhcp6 = NULL;
+#endif /* LWIP_IPV6_DHCP6 */
 #if LWIP_NETIF_STATUS_CALLBACK
   netif->status_callback = NULL;
 #endif /* LWIP_NETIF_STATUS_CALLBACK */
@@ -163,6 +191,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
 #if LWIP_IGMP
   netif->igmp_mac_filter = NULL;
 #endif /* LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+  netif->mld_mac_filter = NULL;
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
 #if ENABLE_LOOPBACK
   netif->loop_first = NULL;
   netif->loop_last = NULL;
@@ -170,11 +201,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
 
   /* remember netif specific state information data */
   netif->state = state;
-  netif->num = netifnum++;
+  netif->num = netif_num++;
   netif->input = input;
-#if LWIP_NETIF_HWADDRHINT
-  netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
+  NETIF_SET_HWADDRHINT(netif, NULL);
 #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
   netif->loop_cnt_current = 0;
 #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
@@ -245,6 +274,10 @@ netif_remove(struct netif *netif)
     igmp_stop(netif);
   }
 #endif /* LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+  /* stop MLD processing */
+  mld6_stop(netif);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
   if (netif_is_up(netif)) {
     /* set netif down before removing (call callback function) */
     netif_set_down(netif);
@@ -331,10 +364,10 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
     pcb = tcp_active_pcbs;
     while (pcb != NULL) {
       /* PCB bound to current local interface address? */
-      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
+      if (ip_addr_cmp(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr))
 #if LWIP_AUTOIP
         /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
-        && !ip_addr_islinklocal(&(pcb->local_ip))
+        && !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip))
 #endif /* LWIP_AUTOIP */
         ) {
         /* this connection must be aborted */
@@ -348,11 +381,11 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
     }
     for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
       /* PCB bound to current local interface address? */
-      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
-          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
+      if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) &&
+          (ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) {
         /* The PCB is listening to the old ipaddr and
          * is set to listen to the new one instead */
-        ip_addr_set(&(lpcb->local_ip), ipaddr);
+        ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr);
       }
     }
   }
@@ -459,18 +492,28 @@ void netif_set_up(struct netif *netif)
 
     if (netif->flags & NETIF_FLAG_LINK_UP) {
 #if LWIP_ARP
-    /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
+      /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
       if (netif->flags & (NETIF_FLAG_ETHARP)) {
-      etharp_gratuitous(netif);
-    }
+        etharp_gratuitous(netif);
+      }
 #endif /* LWIP_ARP */
-    
+
 #if LWIP_IGMP
       /* resend IGMP memberships */
       if (netif->flags & NETIF_FLAG_IGMP) {
         igmp_report_groups( netif);
       }
 #endif /* LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+      /* send mld memberships */
+      mld6_report_groups( netif);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+      /* Send Router Solicitation messages. */
+      netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+
     }
   }
 }
@@ -486,13 +529,13 @@ void netif_set_up(struct netif *netif)
 void netif_set_down(struct netif *netif)
 {
   if (netif->flags & NETIF_FLAG_UP) {
-      netif->flags &= ~NETIF_FLAG_UP;
+    netif->flags &= ~NETIF_FLAG_UP;
 #if LWIP_SNMP
-      snmp_get_sysuptime(&netif->ts);
+    snmp_get_sysuptime(&netif->ts);
 #endif
-      
-      NETIF_STATUS_CALLBACK(netif);
-    }
+
+    NETIF_STATUS_CALLBACK(netif);
+  }
 }
 
 #if LWIP_NETIF_STATUS_CALLBACK
@@ -502,7 +545,7 @@ void netif_set_down(struct netif *netif)
 void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
 {
   if (netif) {
-        netif->status_callback = status_callback;
+    netif->status_callback = status_callback;
   }
 }
 #endif /* LWIP_NETIF_STATUS_CALLBACK */
@@ -513,7 +556,7 @@ void netif_set_status_callback(struct netif *netif, netif_status_callback_fn sta
 void netif_set_link_up(struct netif *netif )
 {
   if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
-  netif->flags |= NETIF_FLAG_LINK_UP;
+    netif->flags |= NETIF_FLAG_LINK_UP;
 
 #if LWIP_DHCP
     if (netif->dhcp) {
@@ -529,20 +572,24 @@ void netif_set_link_up(struct netif *netif )
 
     if (netif->flags & NETIF_FLAG_UP) {
 #if LWIP_ARP
-  /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
-  if (netif->flags & NETIF_FLAG_ETHARP) {
-    etharp_gratuitous(netif);
-  }
+      /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ 
+      if (netif->flags & NETIF_FLAG_ETHARP) {
+        etharp_gratuitous(netif);
+      }
 #endif /* LWIP_ARP */
 
 #if LWIP_IGMP
-  /* resend IGMP memberships */
-  if (netif->flags & NETIF_FLAG_IGMP) {
-    igmp_report_groups( netif);
-  }
+      /* resend IGMP memberships */
+      if (netif->flags & NETIF_FLAG_IGMP) {
+        igmp_report_groups( netif);
+      }
 #endif /* LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+      /* send mld memberships */
+      mld6_report_groups( netif);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
     }
-  NETIF_LINK_CALLBACK(netif);
+    NETIF_LINK_CALLBACK(netif);
   }
 }
 
@@ -552,8 +599,8 @@ void netif_set_link_up(struct netif *netif )
 void netif_set_link_down(struct netif *netif )
 {
   if (netif->flags & NETIF_FLAG_LINK_UP) {
-  netif->flags &= ~NETIF_FLAG_LINK_UP;
-  NETIF_LINK_CALLBACK(netif);
+    netif->flags &= ~NETIF_FLAG_LINK_UP;
+    NETIF_LINK_CALLBACK(netif);
   }
 }
 
@@ -618,12 +665,12 @@ netif_loop_output(struct netif *netif, struct pbuf *p,
   clen = pbuf_clen(r);
   /* check for overflow or too many pbuf on queue */
   if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
-    ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
-      pbuf_free(r);
+     ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
+    pbuf_free(r);
     LINK_STATS_INC(link.memerr);
     LINK_STATS_INC(link.drop);
     snmp_inc_ifoutdiscards(stats_if);
-      return ERR_MEM;
+    return ERR_MEM;
   }
   netif->loop_cnt_current += clen;
 #endif /* LWIP_LOOPBACK_MAX_PBUFS */
@@ -750,3 +797,62 @@ netif_poll_all(void)
 }
 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
 #endif /* ENABLE_LOOPBACK */
+
+#if LWIP_IPV6
+s8_t
+netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr)
+{
+  s8_t i;
+  for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+    if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+void
+netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit)
+{
+  u8_t i, addr_index;
+
+  /* Link-local prefix. */
+  netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul);
+  netif->ip6_addr[0].addr[1] = 0;
+
+  /* Generate interface ID. */
+  if (from_mac_48bit) {
+    /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
+    netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
+        ((u32_t)(netif->hwaddr[1]) << 16) |
+        ((u32_t)(netif->hwaddr[2]) << 8) |
+        (0xff));
+    netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) |
+        ((u32_t)(netif->hwaddr[3]) << 16) |
+        ((u32_t)(netif->hwaddr[4]) << 8) |
+        (netif->hwaddr[5]));
+  }
+  else {
+    /* Use hwaddr directly as interface ID. */
+    netif->ip6_addr[0].addr[2] = 0;
+    netif->ip6_addr[0].addr[3] = 0;
+
+    addr_index = 3;
+    for (i = 0; i < 8; i++) {
+      if (i == 4) {
+        addr_index--;
+      }
+      netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03));
+    }
+  }
+
+  /* Set address state. */
+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
+  /* Will perform duplicate address detection (DAD). */
+  netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
+#else
+  /* Consider address valid. */
+  netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
+#endif /* LWIP_IPV6_AUTOCONFIG */
+}
+#endif /* LWIP_IPV6 */
index 7534eeec2aa71fe67a44353546273a41b8ab409d..6c45dbf2b57559f61b3782ed236704b9c812e77d 100644 (file)
    aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
 #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
 
-#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
+#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ
 #define PBUF_POOL_IS_EMPTY()
-#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
-/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
-#ifndef PBUF_POOL_FREE_OOSEQ
-#define PBUF_POOL_FREE_OOSEQ 1
-#endif /* PBUF_POOL_FREE_OOSEQ */
+#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
 
-#if PBUF_POOL_FREE_OOSEQ
+#if !NO_SYS
+#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
 #include "lwip/tcpip.h"
+#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL()  do { \
+  if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \
+      SYS_ARCH_PROTECT(old_level); \
+      pbuf_free_ooseq_pending = 0; \
+      SYS_ARCH_UNPROTECT(old_level); \
+  } } while(0)
+#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
+#endif /* !NO_SYS */
+
+volatile u8_t pbuf_free_ooseq_pending;
 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
-static u8_t pbuf_free_ooseq_queued;
+
 /**
  * Attempt to reclaim some memory from queued out-of-sequence TCP segments
  * if we run out of pool pbufs. It's better to give priority to new packets
@@ -104,51 +111,66 @@ static u8_t pbuf_free_ooseq_queued;
  * This must be done in the correct thread context therefore this function
  * can only be used with NO_SYS=0 and through tcpip_callback.
  */
-static void
-pbuf_free_ooseq(void* arg)
+#if !NO_SYS
+static
+#endif /* !NO_SYS */
+void
+pbuf_free_ooseq(void)
 {
   struct tcp_pcb* pcb;
   SYS_ARCH_DECL_PROTECT(old_level);
-  LWIP_UNUSED_ARG(arg);
 
   SYS_ARCH_PROTECT(old_level);
-  pbuf_free_ooseq_queued = 0;
+  pbuf_free_ooseq_pending = 0;
   SYS_ARCH_UNPROTECT(old_level);
 
   for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
-      if (NULL != pcb->ooseq) {
+    if (NULL != pcb->ooseq) {
       /** Free the ooseq pbufs of one PCB only */
       LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
-        tcp_segs_free(pcb->ooseq);
-        pcb->ooseq = NULL;
+      tcp_segs_free(pcb->ooseq);
+      pcb->ooseq = NULL;
       return;
     }
-      }
+  }
+}
+
+#if !NO_SYS
+/**
+ * Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq().
+ */
+static void
+pbuf_free_ooseq_callback(void *arg)
+{
+  LWIP_UNUSED_ARG(arg);
+  pbuf_free_ooseq();
 }
+#endif /* !NO_SYS */
 
 /** Queue a call to pbuf_free_ooseq if not already queued. */
 static void
 pbuf_pool_is_empty(void)
 {
+#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL
+  SYS_ARCH_DECL_PROTECT(old_level);
+  SYS_ARCH_PROTECT(old_level);
+  pbuf_free_ooseq_pending = 1;
+  SYS_ARCH_UNPROTECT(old_level);
+#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
   u8_t queued;
   SYS_ARCH_DECL_PROTECT(old_level);
-
   SYS_ARCH_PROTECT(old_level);
-  queued = pbuf_free_ooseq_queued;
-  pbuf_free_ooseq_queued = 1;
+  queued = pbuf_free_ooseq_pending;
+  pbuf_free_ooseq_pending = 1;
   SYS_ARCH_UNPROTECT(old_level);
 
   if(!queued) {
     /* queue a call to pbuf_free_ooseq if not already queued */
-    if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
-      SYS_ARCH_PROTECT(old_level);
-      pbuf_free_ooseq_queued = 0;
-      SYS_ARCH_UNPROTECT(old_level);
-    }
+    PBUF_POOL_FREE_OOSEQ_QUEUE_CALL();
   }
+#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
 }
-#endif /* PBUF_POOL_FREE_OOSEQ */
-#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
+#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
 
 /**
  * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
@@ -190,21 +212,21 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
   LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
 
   /* determine header offset */
-  offset = 0;
   switch (layer) {
   case PBUF_TRANSPORT:
     /* add room for transport (often TCP) layer header */
-    offset += PBUF_TRANSPORT_HLEN;
-    /* FALLTHROUGH */
+    offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
+    break;
   case PBUF_IP:
     /* add room for IP layer header */
-    offset += PBUF_IP_HLEN;
-    /* FALLTHROUGH */
+    offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
+    break;
   case PBUF_LINK:
     /* add room for link layer header */
-    offset += PBUF_LINK_HLEN;
+    offset = PBUF_LINK_HLEN;
     break;
   case PBUF_RAW:
+    offset = 0;
     break;
   default:
     LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
@@ -326,6 +348,67 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
   return p;
 }
 
+#if LWIP_SUPPORT_CUSTOM_PBUF
+/** Initialize a custom pbuf (already allocated).
+ *
+ * @param layer flag to define header size
+ * @param length size of the pbuf's payload
+ * @param type type of the pbuf (only used to treat the pbuf accordingly, as
+ *        this function allocates no memory)
+ * @param p pointer to the custom pbuf to initialize (already allocated)
+ * @param payload_mem pointer to the buffer that is used for payload and headers,
+ *        must be at least big enough to hold 'length' plus the header size,
+ *        may be NULL if set later
+ * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
+ *        big enough to hold 'length' plus the header size
+ */
+struct pbuf*
+pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,
+                    void *payload_mem, u16_t payload_mem_len)
+{
+  u16_t offset;
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
+
+  /* determine header offset */
+  switch (l) {
+  case PBUF_TRANSPORT:
+    /* add room for transport (often TCP) layer header */
+    offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
+    break;
+  case PBUF_IP:
+    /* add room for IP layer header */
+    offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
+    break;
+  case PBUF_LINK:
+    /* add room for link layer header */
+    offset = PBUF_LINK_HLEN;
+    break;
+  case PBUF_RAW:
+    offset = 0;
+    break;
+  default:
+    LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
+    return NULL;
+  }
+
+  if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
+    return NULL;
+  }
+
+  p->pbuf.next = NULL;
+  if (payload_mem != NULL) {
+    p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));
+  } else {
+    p->pbuf.payload = NULL;
+  }
+  p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
+  p->pbuf.len = p->pbuf.tot_len = length;
+  p->pbuf.type = type;
+  p->pbuf.ref = 1;
+  return &p->pbuf;
+}
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
 
 /**
  * Shrink a pbuf chain to a desired length.
@@ -573,15 +656,25 @@ pbuf_free(struct pbuf *p)
       q = p->next;
       LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
       type = p->type;
-      /* is this a pbuf from the pool? */
-      if (type == PBUF_POOL) {
-        memp_free(MEMP_PBUF_POOL, p);
-      /* is this a ROM or RAM referencing pbuf? */
-      } else if (type == PBUF_ROM || type == PBUF_REF) {
-        memp_free(MEMP_PBUF, p);
-      /* type == PBUF_RAM */
-      } else {
-        mem_free(p);
+#if LWIP_SUPPORT_CUSTOM_PBUF
+      /* is this a custom pbuf? */
+      if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
+        struct pbuf_custom *pc = (struct pbuf_custom*)p;
+        LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
+        pc->custom_free_function(p);
+      } else
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+      {
+        /* is this a pbuf from the pool? */
+        if (type == PBUF_POOL) {
+          memp_free(MEMP_PBUF_POOL, p);
+        /* is this a ROM or RAM referencing pbuf? */
+        } else if (type == PBUF_ROM || type == PBUF_REF) {
+          memp_free(MEMP_PBUF, p);
+        /* type == PBUF_RAM */
+        } else {
+          mem_free(p);
+        }
       }
       count++;
       /* proceed to next pbuf */
@@ -903,8 +996,8 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
 /**
  * Creates a single pbuf out of a queue of pbufs.
  *
- * @remark: The source pbuf 'p' is not freed by this function because that can
- *          be illegal in some places!
+ * @remark: Either the source pbuf 'p' is freed by this function or the original
+ *          pbuf 'p' is returned, therefore the caller has to check the result!
  *
  * @param p the source pbuf
  * @param layer pbuf_layer of the new pbuf
@@ -971,3 +1064,115 @@ pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
   return ERR_OK;
 }
 #endif /* LWIP_CHECKSUM_ON_COPY */
+
+ /** Get one byte from the specified position in a pbuf
+ * WARNING: returns zero for offset >= p->tot_len
+ *
+ * @param p pbuf to parse
+ * @param offset offset into p of the byte to return
+ * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
+ */
+u8_t
+pbuf_get_at(struct pbuf* p, u16_t offset)
+{
+  u16_t copy_from = offset;
+  struct pbuf* q = p;
+
+  /* get the correct pbuf */
+  while ((q != NULL) && (q->len <= copy_from)) {
+    copy_from -= q->len;
+    q = q->next;
+  }
+  /* return requested data if pbuf is OK */
+  if ((q != NULL) && (q->len > copy_from)) {
+    return ((u8_t*)q->payload)[copy_from];
+  }
+  return 0;
+}
+
+/** Compare pbuf contents at specified offset with memory s2, both of length n
+ *
+ * @param p pbuf to compare
+ * @param offset offset into p at wich to start comparing
+ * @param s2 buffer to compare
+ * @param n length of buffer to compare
+ * @return zero if equal, nonzero otherwise
+ *         (0xffff if p is too short, diffoffset+1 otherwise)
+ */
+u16_t
+pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)
+{
+  u16_t start = offset;
+  struct pbuf* q = p;
+
+  /* get the correct pbuf */
+  while ((q != NULL) && (q->len <= start)) {
+    start -= q->len;
+    q = q->next;
+  }
+  /* return requested data if pbuf is OK */
+  if ((q != NULL) && (q->len > start)) {
+    u16_t i;
+    for(i = 0; i < n; i++) {
+      u8_t a = pbuf_get_at(q, start + i);
+      u8_t b = ((u8_t*)s2)[i];
+      if (a != b) {
+        return i+1;
+      }
+    }
+    return 0;
+  }
+  return 0xffff;
+}
+
+/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
+ * start_offset.
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ *        return value 'not found'
+ * @param mem search for the contents of this buffer
+ * @param mem_len length of 'mem'
+ * @param start_offset offset into p at which to start searching
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)
+{
+  u16_t i;
+  u16_t max = p->tot_len - mem_len;
+  if (p->tot_len >= mem_len + start_offset) {
+    for(i = start_offset; i <= max; ) {
+      u16_t plus = pbuf_memcmp(p, i, mem, mem_len);
+      if (plus == 0) {
+        return i;
+      } else {
+        i += plus;
+      }
+    }
+  }
+  return 0xFFFF;
+}
+
+/** Find occurrence of substr with length substr_len in pbuf p, start at offset
+ * start_offset
+ * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
+ * the pbuf/source string!
+ *
+ * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
+ *        return value 'not found'
+ * @param substr string to search for in p, maximum length is 0xFFFE
+ * @return 0xFFFF if substr was not found in p or the index where it was found
+ */
+u16_t
+pbuf_strstr(struct pbuf* p, const char* substr)
+{
+  size_t substr_len;
+  if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
+    return 0xFFFF;
+  }
+  substr_len = strlen(substr);
+  if (substr_len >= 0xFFFF) {
+    return 0xFFFF;
+  }
+  return pbuf_memfind(p, substr, (u16_t)substr_len, 0);
+}
index fc71ae3f6949e65c6404057dad282058f2b0a173..2adc8a9649e72468542be52f15a345013bfbdc02 100644 (file)
@@ -49,6 +49,8 @@
 #include "lwip/raw.h"
 #include "lwip/stats.h"
 #include "arch/perf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
 
 #include <string.h>
 
@@ -79,29 +81,47 @@ raw_input(struct pbuf *p, struct netif *inp)
   struct ip_hdr *iphdr;
   s16_t proto;
   u8_t eaten = 0;
+#if LWIP_IPV6
+  struct ip6_hdr *ip6hdr;
+#endif /* LWIP_IPV6 */
+
 
   LWIP_UNUSED_ARG(inp);
 
   iphdr = (struct ip_hdr *)p->payload;
-  proto = IPH_PROTO(iphdr);
+#if LWIP_IPV6
+  if (IPH_V(iphdr) == 6) {
+    ip6hdr = (struct ip6_hdr *)p->payload;
+    proto = IP6H_NEXTH(ip6hdr);
+  }
+  else
+#endif /* LWIP_IPV6 */
+  {
+    proto = IPH_PROTO(iphdr);
+  }
 
   prev = NULL;
   pcb = raw_pcbs;
   /* loop through all raw pcbs until the packet is eaten by one */
   /* this allows multiple pcbs to match against the packet by design */
   while ((eaten == 0) && (pcb != NULL)) {
-    if ((pcb->protocol == proto) &&
-        (ip_addr_isany(&pcb->local_ip) ||
-         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
+    if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
+        (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
+         ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
 #if IP_SOF_BROADCAST_RECV
       /* broadcast filter? */
-      if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
+      if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
+#if LWIP_IPV6
+          && !PCB_ISIPV6(pcb)
+#endif /* LWIP_IPV6 */
+          )
 #endif /* IP_SOF_BROADCAST_RECV */
       {
         /* receive callback function available? */
-        if (pcb->recv != NULL) {
+        if (pcb->recv.ip4 != NULL) {
           /* the receive callback function did not eat the packet? */
-          if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
+          eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
+          if (eaten != 0) {
             /* receive function ate the packet */
             p = NULL;
             eaten = 1;
@@ -141,7 +161,7 @@ raw_input(struct pbuf *p, struct netif *inp)
 err_t
 raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
 {
-  ip_addr_set(&pcb->local_ip, ipaddr);
+  ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
   return ERR_OK;
 }
 
@@ -161,7 +181,7 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
 err_t
 raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
 {
-  ip_addr_set(&pcb->remote_ip, ipaddr);
+  ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
   return ERR_OK;
 }
 
@@ -183,7 +203,7 @@ void
 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
 {
   /* remember recv() callback and user data */
-  pcb->recv = recv;
+  pcb->recv.ip4 = recv;
   pcb->recv_arg = recv_arg;
 }
 
@@ -204,13 +224,21 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
 {
   err_t err;
   struct netif *netif;
-  ip_addr_t *src_ip;
+  ipX_addr_t *src_ip;
   struct pbuf *q; /* q will be sent down the stack */
-  
+  s16_t header_size;
+  ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);
+
   LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
-  
+
+  header_size = (
+#if LWIP_IPV6
+    PCB_ISIPV6(pcb) ? IP6_HLEN :
+#endif /* LWIP_IPV6 */
+    IP_HLEN);
+
   /* not enough space to add an IP header to first pbuf in given p chain? */
-  if (pbuf_header(p, IP_HLEN)) {
+  if (pbuf_header(p, header_size)) {
     /* allocate header in new pbuf */
     q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
     /* new header pbuf could not be allocated? */
@@ -218,22 +246,25 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
       LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
       return ERR_MEM;
     }
-    /* chain header q in front of given pbuf p */
-    pbuf_chain(q, p);
+    if (p->tot_len != 0) {
+      /* chain header q in front of given pbuf p */
+      pbuf_chain(q, p);
+    }
     /* { first pbuf q points to header pbuf } */
     LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
   }  else {
     /* first pbuf q equals given pbuf */
     q = p;
-    if(pbuf_header(q, -IP_HLEN)) {
+    if(pbuf_header(q, -header_size)) {
       LWIP_ASSERT("Can't restore header we just removed!", 0);
       return ERR_MEM;
     }
   }
 
-  if ((netif = ip_route(ipaddr)) == NULL) {
-    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-      ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
+  netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
+  if (netif == NULL) {
+    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
+    ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
     /* free any temporary header pbuf allocated by pbuf_header() */
     if (q != p) {
       pbuf_free(q);
@@ -242,32 +273,42 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
   }
 
 #if IP_SOF_BROADCAST
-  /* broadcast filter? */
-  if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
-    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
-    /* free any temporary header pbuf allocated by pbuf_header() */
-    if (q != p) {
-      pbuf_free(q);
+#if LWIP_IPV6
+  /* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */
+  if (!PCB_ISIPV6(pcb))
+#endif /* LWIP_IPV6 */
+  {
+    /* broadcast filter? */
+    if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
+      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
+      /* free any temporary header pbuf allocated by pbuf_header() */
+      if (q != p) {
+        pbuf_free(q);
+      }
+      return ERR_VAL;
     }
-    return ERR_VAL;
   }
 #endif /* IP_SOF_BROADCAST */
 
-  if (ip_addr_isany(&pcb->local_ip)) {
+  if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
     /* use outgoing network interface IP address as source address */
-    src_ip = &(netif->ip_addr);
+    src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
+#if LWIP_IPV6
+    if (src_ip == NULL) {
+      if (q != p) {
+        pbuf_free(q);
+      }
+      return ERR_RTE;
+    }
+#endif /* LWIP_IPV6 */
   } else {
     /* use RAW PCB local IP address as source address */
-    src_ip = &(pcb->local_ip);
+    src_ip = &pcb->local_ip;
   }
 
-#if LWIP_NETIF_HWADDRHINT
-  netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
-#if LWIP_NETIF_HWADDRHINT
-  netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
+  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
+  err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
+  NETIF_SET_HWADDRHINT(netif, NULL);
 
   /* did we chain a header earlier? */
   if (q != p) {
@@ -287,7 +328,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
 err_t
 raw_send(struct raw_pcb *pcb, struct pbuf *p)
 {
-  return raw_sendto(pcb, p, &pcb->remote_ip);
+  return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip));
 }
 
 /**
@@ -349,4 +390,26 @@ raw_new(u8_t proto)
   return pcb;
 }
 
+#if LWIP_IPV6
+/**
+ * Create a RAW PCB for IPv6.
+ *
+ * @return The RAW PCB which was created. NULL if the PCB data structure
+ * could not be allocated.
+ *
+ * @param proto the protocol number (next header) of the IPv6 packet payload
+ *              (e.g. IP6_NEXTH_ICMP6)
+ *
+ * @see raw_remove()
+ */
+struct raw_pcb *
+raw_new_ip6(u8_t proto)
+{
+  struct raw_pcb *pcb;
+  pcb = raw_new(proto);
+  ip_set_v6(pcb, 1);
+  return pcb;
+}
+#endif /* LWIP_IPV6 */
+
 #endif /* LWIP_RAW */
index 5ed9fcd66a26c3cb2c9f03cb8f117e79c29f7f25..dcd3b62c1ed6f3da5b2229145bee8f0aa55822e6 100644 (file)
 #include "lwip/netif.h"
 #include "lwip/ip.h"
 #include "lwip/ip_frag.h"
+#include "lwip/mem.h"
 #include "lwip/tcp_impl.h"
 #include "lwip/udp.h"
 #include "lwip/snmp_asn1.h"
 #include "lwip/snmp_structs.h"
+#include "lwip/sys.h"
 #include "netif/etharp.h"
 
 /**
@@ -71,7 +73,7 @@
 #endif
 
 #ifndef SNMP_GET_SYSUPTIME
-#define SNMP_GET_SYSUPTIME(sysuptime)
+#define SNMP_GET_SYSUPTIME(sysuptime)  (sysuptime = (sys_now() / 10))
 #endif
 
 static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
@@ -1795,7 +1797,7 @@ void snmp_insert_udpidx_tree(struct udp_pcb *pcb)
   u8_t level;
 
   LWIP_ASSERT("pcb != NULL", pcb != NULL);
-  snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+  snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]);
   udpidx[4] = pcb->local_port;
 
   udp_rn = &udp_root;
@@ -1848,7 +1850,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
   u8_t bindings, fc, level, del_cnt;
 
   LWIP_ASSERT("pcb != NULL", pcb != NULL);
-  snmp_iptooid(&pcb->local_ip, &udpidx[0]);
+  snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]);
   udpidx[4] = pcb->local_port;
 
   /* count PCBs for a given binding
@@ -1857,7 +1859,7 @@ void snmp_delete_udpidx_tree(struct udp_pcb *pcb)
   npcb = udp_pcbs;
   while ((npcb != NULL))
   {
-    if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) &&
+    if (ipX_addr_cmp(0, &npcb->local_ip, &pcb->local_ip) &&
         (npcb->local_port == udpidx[4]))
     {
       bindings++;
@@ -3879,17 +3881,17 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
 {
   u8_t id;
   struct udp_pcb *pcb;
-  ip_addr_t ip;
+  ipX_addr_t ip;
   u16_t port;
 
   LWIP_UNUSED_ARG(len);
-  snmp_oidtoip(&od->id_inst_ptr[1], &ip);
+  snmp_oidtoip(&od->id_inst_ptr[1], (ip_addr_t*)&ip);
   LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff));
   port = (u16_t)od->id_inst_ptr[5];
 
   pcb = udp_pcbs;
   while ((pcb != NULL) &&
-         !(ip_addr_cmp(&pcb->local_ip, &ip) &&
+         !(ipX_addr_cmp(0, &pcb->local_ip, &ip) &&
            (pcb->local_port == port)))
   {
     pcb = pcb->next;
@@ -3903,8 +3905,8 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value)
     {
       case 1: /* udpLocalAddress */
         {
-          ip_addr_t *dst = (ip_addr_t*)value;
-          *dst = pcb->local_ip;
+          ipX_addr_t *dst = (ipX_addr_t*)value;
+          ipX_addr_copy(0, *dst, pcb->local_ip);
         }
         break;
       case 2: /* udpLocalPort */
index 402b78f95e226474563b2ea20cd0e8f750313c7f..2dfb55b253a2e9c9068457afdf8ae350fcdc5b7c 100644 (file)
@@ -818,53 +818,53 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t
   /* suppress unused argument warning */
   LWIP_UNUSED_ARG(arg);
 
-    /* traverse input message process list, look for SNMP_MSG_EMPTY */
-    msg_ps = &msg_input_list[0];
-    req_idx = 0;
+  /* traverse input message process list, look for SNMP_MSG_EMPTY */
+  msg_ps = &msg_input_list[0];
+  req_idx = 0;
   while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
-    {
-      req_idx++;
-      msg_ps++;
-    }
+  {
+    req_idx++;
+    msg_ps++;
+  }
   if (req_idx == SNMP_CONCURRENT_REQUESTS)
-    {
+  {
     /* exceeding number of concurrent requests */
     pbuf_free(p);
     return;
   }
 
-      /* accepting request */
-      snmp_inc_snmpinpkts();
-      /* record used 'protocol control block' */
-      msg_ps->pcb = pcb;
-      /* source address (network order) */
-      msg_ps->sip = *addr;
-      /* source port (host order (lwIP oddity)) */
-      msg_ps->sp = port;
-
-      /* check total length, version, community, pdu type */
-      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
-        /* Only accept requests and requests without error (be robust) */
-        /* Reject response and trap headers or error requests as input! */
+  /* accepting request */
+  snmp_inc_snmpinpkts();
+  /* record used 'protocol control block' */
+  msg_ps->pcb = pcb;
+  /* source address (network order) */
+  msg_ps->sip = *addr;
+  /* source port (host order (lwIP oddity)) */
+  msg_ps->sp = port;
+
+  /* check total length, version, community, pdu type */
+  err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
+  /* Only accept requests and requests without error (be robust) */
+  /* Reject response and trap headers or error requests as input! */
   if ((err_ret != ERR_OK) ||
       ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
        (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
        (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
       ((msg_ps->error_status != SNMP_ES_NOERROR) ||
        (msg_ps->error_index != 0)) )
-      {
+  {
     /* header check failed drop request silently, do not return error! */
     pbuf_free(p);
     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
     return;
   }
-        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
 
-        /* Builds a list of variable bindings. Copy the varbinds from the pbuf
-          chain to glue them when these are divided over two or more pbuf's. */
-        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
-          /* we've decoded the incoming message, release input msg now */
-          pbuf_free(p);
+  /* Builds a list of variable bindings. Copy the varbinds from the pbuf
+    chain to glue them when these are divided over two or more pbuf's. */
+  err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
+  /* we've decoded the incoming message, release input msg now */
+  pbuf_free(p);
   if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
   {
     /* varbind-list decode failed, or varbind list empty.
@@ -874,17 +874,17 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t
     return;
   }
 
-          msg_ps->error_status = SNMP_ES_NOERROR;
-          msg_ps->error_index = 0;
-          /* find object for each variable binding */
-          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
-          /* first variable binding from list to inspect */
-          msg_ps->vb_idx = 0;
+  msg_ps->error_status = SNMP_ES_NOERROR;
+  msg_ps->error_index = 0;
+  /* find object for each variable binding */
+  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
+  /* first variable binding from list to inspect */
+  msg_ps->vb_idx = 0;
 
-          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
 
-          /* handle input event and as much objects as possible in one go */
-          snmp_msg_event(req_idx);
+  /* handle input event and as much objects as possible in one go */
+  snmp_msg_event(req_idx);
 }
 
 /**
index eec6a05bb9cb80e662a7d804a30a21db25b27d8e..5bdd5a230c33f3f4ff81218b58e8d40a34655e19 100644 (file)
@@ -69,7 +69,7 @@ void stats_init(void)
 
 #if LWIP_STATS_DISPLAY
 void
-stats_display_proto(struct stats_proto *proto, char *name)
+stats_display_proto(struct stats_proto *proto, const char *name)
 {
   LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
   LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); 
@@ -88,9 +88,9 @@ stats_display_proto(struct stats_proto *proto, char *name)
 
 #if IGMP_STATS
 void
-stats_display_igmp(struct stats_igmp *igmp)
+stats_display_igmp(struct stats_igmp *igmp, const char *name)
 {
-  LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
+  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
   LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); 
   LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); 
   LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); 
@@ -110,7 +110,7 @@ stats_display_igmp(struct stats_igmp *igmp)
 
 #if MEM_STATS || MEMP_STATS
 void
-stats_display_mem(struct stats_mem *mem, char *name)
+stats_display_mem(struct stats_mem *mem, const char *name)
 {
   LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
   LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); 
@@ -139,15 +139,15 @@ void
 stats_display_sys(struct stats_sys *sys)
 {
   LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
-  LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); 
-  LWIP_PLATFORM_DIAG(("sem.max:  %"U32_F"\n\t", (u32_t)sys->sem.max)); 
-  LWIP_PLATFORM_DIAG(("sem.err:  %"U32_F"\n\t", (u32_t)sys->sem.err)); 
+  LWIP_PLATFORM_DIAG(("sem.used:  %"U32_F"\n\t", (u32_t)sys->sem.used)); 
+  LWIP_PLATFORM_DIAG(("sem.max:   %"U32_F"\n\t", (u32_t)sys->sem.max)); 
+  LWIP_PLATFORM_DIAG(("sem.err:   %"U32_F"\n\t", (u32_t)sys->sem.err)); 
   LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); 
   LWIP_PLATFORM_DIAG(("mutex.max:  %"U32_F"\n\t", (u32_t)sys->mutex.max)); 
   LWIP_PLATFORM_DIAG(("mutex.err:  %"U32_F"\n\t", (u32_t)sys->mutex.err)); 
-  LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); 
-  LWIP_PLATFORM_DIAG(("mbox.max:  %"U32_F"\n\t", (u32_t)sys->mbox.max)); 
-  LWIP_PLATFORM_DIAG(("mbox.err:  %"U32_F"\n\t", (u32_t)sys->mbox.err)); 
+  LWIP_PLATFORM_DIAG(("mbox.used:  %"U32_F"\n\t", (u32_t)sys->mbox.used)); 
+  LWIP_PLATFORM_DIAG(("mbox.max:   %"U32_F"\n\t", (u32_t)sys->mbox.max)); 
+  LWIP_PLATFORM_DIAG(("mbox.err:   %"U32_F"\n\t", (u32_t)sys->mbox.err)); 
 }
 #endif /* SYS_STATS */
 
@@ -159,9 +159,14 @@ stats_display(void)
   LINK_STATS_DISPLAY();
   ETHARP_STATS_DISPLAY();
   IPFRAG_STATS_DISPLAY();
+  IP6_FRAG_STATS_DISPLAY();
   IP_STATS_DISPLAY();
+  ND6_STATS_DISPLAY();
+  IP6_STATS_DISPLAY();
   IGMP_STATS_DISPLAY();
+  MLD6_STATS_DISPLAY();
   ICMP_STATS_DISPLAY();
+  ICMP6_STATS_DISPLAY();
   UDP_STATS_DISPLAY();
   TCP_STATS_DISPLAY();
   MEM_STATS_DISPLAY();
index 6eb8972a09dc159d3aae7079f37e9f88e7c16dc6..5ae323e397542cb9dfd1f98486a9bcae21f24aa3 100644 (file)
 #include "lwip/tcp_impl.h"
 #include "lwip/debug.h"
 #include "lwip/stats.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/nd6.h"
 
 #include <string.h>
 
-const char *tcp_state_str[] = {
+const char * const tcp_state_str[] = {
   "CLOSED",      
   "LISTEN",      
   "SYN_SENT",    
@@ -79,19 +82,19 @@ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
 /* The TCP PCB lists. */
 
 /** List of all TCP PCBs bound but not yet (connected || listening) */
-struct tcp_pcb *tcp_bound_pcbs;  
+struct tcp_pcb *tcp_bound_pcbs;
 /** List of all TCP PCBs in LISTEN state */
 union tcp_listen_pcbs_t tcp_listen_pcbs;
 /** List of all TCP PCBs that are in a state in which
  * they accept or send data. */
-struct tcp_pcb *tcp_active_pcbs;  
+struct tcp_pcb *tcp_active_pcbs;
 /** List of all TCP PCBs in TIME-WAIT state */
 struct tcp_pcb *tcp_tw_pcbs;
 
 #define NUM_TCP_PCB_LISTS               4
 #define NUM_TCP_PCB_LISTS_NO_TIME_WAIT  3
 /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
-struct tcp_pcb **tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
+struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
   &tcp_active_pcbs, &tcp_tw_pcbs};
 
 /** Only used for temporary storage. */
@@ -148,7 +151,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
       /* don't call tcp_abort here: we must not deallocate the pcb since
          that might not be expected when calling tcp_close */
       tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
-        pcb->local_port, pcb->remote_port);
+               pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
 
       tcp_pcb_purge(pcb);
 
@@ -173,7 +176,9 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
      * is erroneous, but this should never happen as the pcb has in those cases
      * been freed, and so any remaining handles are bogus. */
     err = ERR_OK;
-    TCP_RMV(&tcp_bound_pcbs, pcb);
+    if (pcb->local_port != 0) {
+      TCP_RMV(&tcp_bound_pcbs, pcb);
+    }
     memp_free(MEMP_TCP_PCB, pcb);
     pcb = NULL;
     break;
@@ -316,8 +321,6 @@ void
 tcp_abandon(struct tcp_pcb *pcb, int reset)
 {
   u32_t seqno, ackno;
-  u16_t remote_port, local_port;
-  ip_addr_t remote_ip, local_ip;
 #if LWIP_CALLBACK_API  
   tcp_err_fn errf;
 #endif /* LWIP_CALLBACK_API */
@@ -335,10 +338,6 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
   } else {
     seqno = pcb->snd_nxt;
     ackno = pcb->rcv_nxt;
-    ip_addr_copy(local_ip, pcb->local_ip);
-    ip_addr_copy(remote_ip, pcb->remote_ip);
-    local_port = pcb->local_port;
-    remote_port = pcb->remote_port;
 #if LWIP_CALLBACK_API
     errf = pcb->errf;
 #endif /* LWIP_CALLBACK_API */
@@ -355,12 +354,12 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
       tcp_segs_free(pcb->ooseq);
     }
 #endif /* TCP_QUEUE_OOSEQ */
-    memp_free(MEMP_TCP_PCB, pcb);
-    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
     if (reset) {
       LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
-      tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
+      tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
     }
+    memp_free(MEMP_TCP_PCB, pcb);
+    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
   }
 }
 
@@ -391,6 +390,7 @@ tcp_abort(struct tcp_pcb *pcb)
  *        to any local address
  * @param port the local port to bind to
  * @return ERR_USE if the port is already in use
+ *         ERR_VAL if bind failed because the PCB is not in a valid state
  *         ERR_OK if bound
  */
 err_t
@@ -400,7 +400,7 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
   int max_pcb_list = NUM_TCP_PCB_LISTS;
   struct tcp_pcb *cpcb;
 
-  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
+  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL);
 
 #if SO_REUSE
   /* Unless the REUSEADDR flag is set,
@@ -408,11 +408,9 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
      We do not dump TIME_WAIT pcb's; they can still be matched by incoming
      packets using both local and remote IP addresses and ports to distinguish.
    */
-#if SO_REUSE
   if ((pcb->so_options & SOF_REUSEADDR) != 0) {
     max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
   }
-#endif /* SO_REUSE */
 #endif /* SO_REUSE */
 
   if (port == 0) {
@@ -422,7 +420,7 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
   /* Check if the address already is in use (on all lists) */
   for (i = 0; i < max_pcb_list; i++) {
     for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
-    if (cpcb->local_port == port) {
+      if (cpcb->local_port == port) {
 #if SO_REUSE
         /* Omit checking for the same port if both pcbs have REUSEADDR set.
            For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
@@ -431,18 +429,20 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
           ((cpcb->so_options & SOF_REUSEADDR) == 0))
 #endif /* SO_REUSE */
         {
-      if (ip_addr_isany(&(cpcb->local_ip)) ||
-          ip_addr_isany(ipaddr) ||
-          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
-        return ERR_USE;
+          /* @todo: check accept_any_ip_version */
+          if (IP_PCB_IPVER_EQ(pcb, cpcb) &&
+              (ipX_addr_isany(PCB_ISIPV6(pcb), &cpcb->local_ip) ||
+              ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr)) ||
+              ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, ip_2_ipX(ipaddr)))) {
+            return ERR_USE;
+          }
+        }
       }
     }
   }
-    }
-  }
 
-  if (!ip_addr_isany(ipaddr)) {
-    pcb->local_ip = *ipaddr;
+  if (!ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr))) {
+    ipX_addr_set(PCB_ISIPV6(pcb), &pcb->local_ip, ip_2_ipX(ipaddr));
   }
   pcb->local_port = port;
   TCP_REG(&tcp_bound_pcbs, pcb);
@@ -496,8 +496,9 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
        is declared (listen-/connection-pcb), we have to make sure now that
        this port is only used once for every local IP. */
     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-      if (lpcb->local_port == pcb->local_port) {
-        if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
+      if ((lpcb->local_port == pcb->local_port) &&
+          IP_PCB_IPVER_EQ(pcb, lpcb)) {
+        if (ipX_addr_cmp(PCB_ISIPV6(pcb), &lpcb->local_ip, &pcb->local_ip)) {
           /* this address/port is already used */
           return NULL;
         }
@@ -517,8 +518,14 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
   lpcb->so_options |= SOF_ACCEPTCONN;
   lpcb->ttl = pcb->ttl;
   lpcb->tos = pcb->tos;
-  ip_addr_copy(lpcb->local_ip, pcb->local_ip);
-  TCP_RMV(&tcp_bound_pcbs, pcb);
+#if LWIP_IPV6
+  PCB_ISIPV6(lpcb) = PCB_ISIPV6(pcb);
+  lpcb->accept_any_ip_version = 0;
+#endif /* LWIP_IPV6 */
+  ipX_addr_copy(PCB_ISIPV6(pcb), lpcb->local_ip, pcb->local_ip);
+  if (pcb->local_port != 0) {
+    TCP_RMV(&tcp_bound_pcbs, pcb);
+  }
   memp_free(MEMP_TCP_PCB, pcb);
 #if LWIP_CALLBACK_API
   lpcb->accept = tcp_accept_null;
@@ -531,7 +538,28 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
   return (struct tcp_pcb *)lpcb;
 }
 
-/** 
+#if LWIP_IPV6
+/**
+ * Same as tcp_listen_with_backlog, but allows to accept IPv4 and IPv6
+ * connections, if the pcb's local address is set to ANY.
+ */
+struct tcp_pcb *
+tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
+{
+  struct tcp_pcb *lpcb;
+
+  if (!ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
+    return NULL;
+  }
+  lpcb = tcp_listen_with_backlog(pcb, backlog);
+  if (lpcb != NULL) {
+    ((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1;
+  }
+  return lpcb;
+}
+#endif /* LWIP_IPV6 */
+
+/**
  * Update the state that tracks the available window space to advertise.
  *
  * Returns how much extra window would be advertised if we sent an
@@ -573,6 +601,9 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
 {
   int wnd_inflation;
 
+  /* pcb->state LISTEN not allowed here */
+  LWIP_ASSERT("don't call tcp_recved for listen-pcbs",
+    pcb->state != LISTEN);
   LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
               len <= 0xffff - pcb->rcv_wnd );
 
@@ -608,23 +639,25 @@ tcp_new_port(void)
   int i;
   struct tcp_pcb *pcb;
 #ifndef TCP_LOCAL_PORT_RANGE_START
-#define TCP_LOCAL_PORT_RANGE_START 4096
-#define TCP_LOCAL_PORT_RANGE_END   0x7fff
+/* From http://www.iana.org/assignments/port-numbers:
+   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
+#define TCP_LOCAL_PORT_RANGE_START  0xc000
+#define TCP_LOCAL_PORT_RANGE_END    0xffff
 #endif
   static u16_t port = TCP_LOCAL_PORT_RANGE_START;
   
  again:
-  if (++port > TCP_LOCAL_PORT_RANGE_END) {
+  if (port++ == TCP_LOCAL_PORT_RANGE_END) {
     port = TCP_LOCAL_PORT_RANGE_START;
   }
   /* Check all PCB lists. */
-  for (i = 1; i < NUM_TCP_PCB_LISTS; i++) {  
+  for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {
     for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
-    if (pcb->local_port == port) {
-      goto again;
+      if (pcb->local_port == port) {
+        goto again;
+      }
     }
   }
-  }
   return port;
 }
 
@@ -646,30 +679,34 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
 {
   err_t ret;
   u32_t iss;
+  u16_t old_local_port;
 
-  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
+  LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);
 
   LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
   if (ipaddr != NULL) {
-    pcb->remote_ip = *ipaddr;
+    ipX_addr_set(PCB_ISIPV6(pcb), &pcb->remote_ip, ip_2_ipX(ipaddr));
   } else {
     return ERR_VAL;
   }
   pcb->remote_port = port;
 
   /* check if we have a route to the remote host */
-  if (ip_addr_isany(&(pcb->local_ip))) {
+  if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
     /* no local IP address set, yet. */
-    struct netif *netif = ip_route(&(pcb->remote_ip));
-    if (netif == NULL) {
+    struct netif *netif;
+    ipX_addr_t *local_ip;
+    ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip);
+    if ((netif == NULL) || (local_ip == NULL)) {
       /* Don't even try to send a SYN packet if we have no route
          since that will fail. */
       return ERR_RTE;
     }
-    /* Use the netif's IP address as local address. */
-    ip_addr_copy(pcb->local_ip, netif->ip_addr);
+    /* Use the address as local address of the pcb. */
+    ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip);
   }
 
+  old_local_port = pcb->local_port;
   if (pcb->local_port == 0) {
     pcb->local_port = tcp_new_port();
   }
@@ -679,13 +716,14 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
        now that the 5-tuple is unique. */
     struct tcp_pcb *cpcb;
     int i;
-    /* Don't check listen PCBs, check bound-, active- and TIME-WAIT PCBs. */
-    for (i = 1; i < NUM_TCP_PCB_LISTS; i++) {
+    /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
+    for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
       for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
         if ((cpcb->local_port == pcb->local_port) &&
             (cpcb->remote_port == port) &&
-            ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
-            ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
+            IP_PCB_IPVER_EQ(cpcb, pcb) &&
+            ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, &pcb->local_ip) &&
+            ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->remote_ip, ip_2_ipX(ipaddr))) {
           /* linux returns EISCONN here, but ERR_USE should be OK for us */
           return ERR_USE;
         }
@@ -706,13 +744,13 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
      The send MSS is updated when an MSS option is received. */
   pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
 #if TCP_CALCULATE_EFF_SEND_MSS
-  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
+  pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb));
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
   pcb->cwnd = 1;
   pcb->ssthresh = pcb->mss * 10;
-#if LWIP_CALLBACK_API  
+#if LWIP_CALLBACK_API
   pcb->connected = connected;
-#else /* LWIP_CALLBACK_API */  
+#else /* LWIP_CALLBACK_API */
   LWIP_UNUSED_ARG(connected);
 #endif /* LWIP_CALLBACK_API */
 
@@ -721,14 +759,16 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
   if (ret == ERR_OK) {
     /* SYN segment was enqueued, changed the pcbs state now */
     pcb->state = SYN_SENT;
-  TCP_RMV(&tcp_bound_pcbs, pcb);
-  TCP_REG(&tcp_active_pcbs, pcb);
-  snmp_inc_tcpactiveopens();
-  
+    if (old_local_port != 0) {
+      TCP_RMV(&tcp_bound_pcbs, pcb);
+    }
+    TCP_REG(&tcp_active_pcbs, pcb);
+    snmp_inc_tcpactiveopens();
+
     tcp_output(pcb);
   }
   return ret;
-} 
+}
 
 /**
  * Called every 500 ms and implements the retransmission timer and the timer that
@@ -740,7 +780,7 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
 void
 tcp_slowtmr(void)
 {
-  struct tcp_pcb *pcb, *pcb2, *prev;
+  struct tcp_pcb *pcb, *prev;
   u16_t eff_wnd;
   u8_t pcb_remove;      /* flag if a PCB should be removed */
   u8_t pcb_reset;       /* flag if a RST should be sent when removing */
@@ -831,21 +871,21 @@ tcp_slowtmr(void)
     }
 
     /* Check if KEEPALIVE should be sent */
-    if((pcb->so_options & SOF_KEEPALIVE) && 
-       ((pcb->state == ESTABLISHED) || 
+    if((pcb->so_options & SOF_KEEPALIVE) &&
+       ((pcb->state == ESTABLISHED) ||
         (pcb->state == CLOSE_WAIT))) {
 #if LWIP_TCP_KEEPALIVE
-      if((u32_t)(tcp_ticks - pcb->tmr) > 
+      if((u32_t)(tcp_ticks - pcb->tmr) >
          (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
          / TCP_SLOW_INTERVAL)
 #else      
-      if((u32_t)(tcp_ticks - pcb->tmr) > 
+      if((u32_t)(tcp_ticks - pcb->tmr) >
          (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
 #endif /* LWIP_TCP_KEEPALIVE */
       {
-        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
-                                ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
-                                ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to "));
+        ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
+        LWIP_DEBUGF(TCP_DEBUG, ("\n"));
         
         ++pcb_remove;
         ++pcb_reset;
@@ -868,7 +908,7 @@ tcp_slowtmr(void)
     /* If this PCB has queued out of sequence data, but has been
        inactive for too long, will drop the data (it will eventually
        be retransmitted). */
-#if TCP_QUEUE_OOSEQ    
+#if TCP_QUEUE_OOSEQ
     if (pcb->ooseq != NULL &&
         (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
       tcp_segs_free(pcb->ooseq);
@@ -896,7 +936,8 @@ tcp_slowtmr(void)
 
     /* If the PCB should be removed, do it. */
     if (pcb_remove) {
-      tcp_pcb_purge(pcb);      
+      struct tcp_pcb *pcb2;
+      tcp_pcb_purge(pcb);
       /* Remove PCB from tcp_active_pcbs list. */
       if (prev != NULL) {
         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
@@ -910,12 +951,12 @@ tcp_slowtmr(void)
       TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
       if (pcb_reset) {
         tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
-          pcb->local_port, pcb->remote_port);
+                 pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb));
       }
 
-      pcb2 = pcb->next;
-      memp_free(MEMP_TCP_PCB, pcb);
-      pcb = pcb2;
+      pcb2 = pcb;
+      pcb = pcb->next;
+      memp_free(MEMP_TCP_PCB, pcb2);
     } else {
       /* get the 'next' element now and work with 'prev' below (in case of abort) */
       prev = pcb;
@@ -937,7 +978,7 @@ tcp_slowtmr(void)
 
   
   /* Steps through all of the TIME-WAIT PCBs. */
-  prev = NULL;    
+  prev = NULL;
   pcb = tcp_tw_pcbs;
   while (pcb != NULL) {
     LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
@@ -952,7 +993,8 @@ tcp_slowtmr(void)
 
     /* If the PCB should be removed, do it. */
     if (pcb_remove) {
-      tcp_pcb_purge(pcb);      
+      struct tcp_pcb *pcb2;
+      tcp_pcb_purge(pcb);
       /* Remove PCB from tcp_tw_pcbs list. */
       if (prev != NULL) {
         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
@@ -962,9 +1004,9 @@ tcp_slowtmr(void)
         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
         tcp_tw_pcbs = pcb->next;
       }
-      pcb2 = pcb->next;
-      memp_free(MEMP_TCP_PCB, pcb);
-      pcb = pcb2;
+      pcb2 = pcb;
+      pcb = pcb->next;
+      memp_free(MEMP_TCP_PCB, pcb2);
     } else {
       prev = pcb;
       pcb = pcb->next;
@@ -999,7 +1041,7 @@ tcp_fasttmr(void)
       }
     }
 
-    /* send delayed ACKs */  
+    /* send delayed ACKs */
     if (pcb && (pcb->flags & TF_ACK_DELAY)) {
       LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
       tcp_ack_now(pcb);
@@ -1100,7 +1142,8 @@ tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
 #endif /* LWIP_CALLBACK_API */
 
 /**
- * Kills the oldest active connection that has lower priority than prio.
+ * Kills the oldest active connection that has the same or lower priority than
+ * 'prio'.
  *
  * @param prio minimum priority
  */
@@ -1130,7 +1173,7 @@ tcp_kill_prio(u8_t prio)
     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
            (void *)inactive, inactivity));
     tcp_abort(inactive);
-  }      
+  }
 }
 
 /**
@@ -1156,7 +1199,7 @@ tcp_kill_timewait(void)
     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
            (void *)inactive, inactivity));
     tcp_abort(inactive);
-  }      
+  }
 }
 
 /**
@@ -1255,6 +1298,24 @@ tcp_new(void)
   return tcp_alloc(TCP_PRIO_NORMAL);
 }
 
+#if LWIP_IPV6
+/**
+ * Creates a new TCP-over-IPv6 protocol control block but doesn't
+ * place it on any of the TCP PCB lists.
+ * The pcb is not put on any list until binding using tcp_bind().
+ *
+ * @return a new tcp_pcb that initially is in state CLOSED
+ */
+struct tcp_pcb *
+tcp_new_ip6(void)
+{
+  struct tcp_pcb * pcb;
+  pcb = tcp_alloc(TCP_PRIO_NORMAL);
+  ip_set_v6(pcb, 1);
+  return pcb;
+}
+#endif /* LWIP_IPV6 */
+
 /**
  * Used to specify the argument that should be passed callback
  * functions.
@@ -1264,7 +1325,9 @@ tcp_new(void)
  */ 
 void
 tcp_arg(struct tcp_pcb *pcb, void *arg)
-{  
+{
+  /* This function is allowed to be called for both listen pcbs and
+     connection pcbs. */
   pcb->callback_arg = arg;
 }
 #if LWIP_CALLBACK_API
@@ -1279,6 +1342,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg)
 void
 tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
 {
+  LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN);
   pcb->recv = recv;
 }
 
@@ -1292,6 +1356,7 @@ tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
 void
 tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
 {
+  LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN);
   pcb->sent = sent;
 }
 
@@ -1306,6 +1371,7 @@ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
 void
 tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
 {
+  LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN);
   pcb->errf = err;
 }
 
@@ -1320,6 +1386,8 @@ tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
 void
 tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
 {
+  /* This function is allowed to be called for both listen pcbs and
+     connection pcbs. */
   pcb->accept = accept;
 }
 #endif /* LWIP_CALLBACK_API */
@@ -1334,6 +1402,7 @@ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
 void
 tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)
 {
+  LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN);
 #if LWIP_CALLBACK_API
   pcb->poll = poll;
 #else /* LWIP_CALLBACK_API */  
@@ -1365,8 +1434,9 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
         tcp_listen_pcbs.listen_pcbs != NULL);
       for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
         if ((lpcb->local_port == pcb->local_port) &&
-            (ip_addr_isany(&lpcb->local_ip) ||
-             ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
+            IP_PCB_IPVER_EQ(pcb, lpcb) &&
+            (ipX_addr_isany(PCB_ISIPV6(lpcb), &lpcb->local_ip) ||
+             ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) {
             /* port and address of the listen pcb match the timed-out pcb */
             LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
               lpcb->accepts_pending > 0);
@@ -1465,14 +1535,36 @@ tcp_next_iss(void)
  * calculating the minimum of TCP_MSS and that netif's mtu (if set).
  */
 u16_t
-tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
+tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest
+#if LWIP_IPV6
+                     , ipX_addr_t *src, u8_t isipv6
+#endif /* LWIP_IPV6 */
+                     )
 {
   u16_t mss_s;
   struct netif *outif;
+  s16_t mtu;
+
+  outif = ipX_route(isipv6, src, dest);
+#if LWIP_IPV6
+  if (isipv6) {
+    /* First look in destination cache, to see if there is a Path MTU. */
+    mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif);
+  } else
+#endif /* LWIP_IPV6 */
+  {
+    if (outif == NULL) {
+      return sendmss;
+    }
+    mtu = outif->mtu;
+  }
 
-  outif = ip_route(addr);
-  if ((outif != NULL) && (outif->mtu != 0)) {
-    mss_s = outif->mtu - IP_HLEN - TCP_HLEN;
+  if (mtu != 0) {
+    mss_s = mtu - IP_HLEN - TCP_HLEN;
+#if LWIP_IPV6
+    /* for IPv6, substract the difference in header size */
+    mss_s -= (IP6_HLEN - IP_HLEN);
+#endif /* LWIP_IPV6 */
     /* RFC 1122, chap 4.2.2.6:
      * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
      * We correct for TCP options in tcp_write(), and don't support IP options.
index b04c44caebd36e5037e49c3638b0c1a84d97f31b..316dc3d9f5104b3c749240939c4a4c6d3610c617 100644 (file)
 #include "lwip/stats.h"
 #include "lwip/snmp.h"
 #include "arch/perf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#if LWIP_ND6_TCP_REACHABILITY_HINTS
+#include "lwip/nd6.h"
+#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
 
 /* These variables are global to all functions involved in the input
    processing of TCP segments. They are set by the tcp_input()
    function. */
 static struct tcp_seg inseg;
 static struct tcp_hdr *tcphdr;
-static struct ip_hdr *iphdr;
 static u32_t seqno, ackno;
 static u8_t flags;
 static u16_t tcplen;
@@ -85,7 +90,7 @@ static err_t tcp_timewait_input(struct tcp_pcb *pcb);
  * the TCP finite state machine. This function is called by the IP layer (in
  * ip_input()).
  *
- * @param p received TCP segment to process (p->payload pointing to the IP header)
+ * @param p received TCP segment to process (p->payload pointing to the TCP header)
  * @param inp network interface on which this segment was received
  */
 void
@@ -99,57 +104,48 @@ tcp_input(struct pbuf *p, struct netif *inp)
 #endif /* SO_REUSE */
   u8_t hdrlen;
   err_t err;
+#if CHECKSUM_CHECK_TCP
+  u16_t chksum;
+#endif /* CHECKSUM_CHECK_TCP */
 
   PERF_START;
 
   TCP_STATS_INC(tcp.recv);
   snmp_inc_tcpinsegs();
 
-  iphdr = (struct ip_hdr *)p->payload;
-  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+  tcphdr = (struct tcp_hdr *)p->payload;
 
 #if TCP_INPUT_DEBUG
   tcp_debug_print(tcphdr);
 #endif
 
-  /* remove header from payload */
-  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
+  /* Check that TCP header fits in payload */
+  if (p->len < sizeof(struct tcp_hdr)) {
     /* drop short packets */
     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
     TCP_STATS_INC(tcp.lenerr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
+    goto dropped;
   }
 
   /* Don't even process incoming broadcasts/multicasts. */
-  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
-      ip_addr_ismulticast(&(iphdr->dest))) {
+  if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) ||
+       ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) {
     TCP_STATS_INC(tcp.proterr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
+    goto dropped;
   }
 
 #if CHECKSUM_CHECK_TCP
   /* Verify TCP checksum. */
-  if (inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest,
-      IP_PROTO_TCP, p->tot_len) != 0) {
+  chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len,
+                             ipX_current_src_addr(), ipX_current_dest_addr());
+  if (chksum != 0) {
       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
-        inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest,
-      IP_PROTO_TCP, p->tot_len)));
-#if TCP_DEBUG
+        chksum));
     tcp_debug_print(tcphdr);
-#endif /* TCP_DEBUG */
     TCP_STATS_INC(tcp.chkerr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
+    goto dropped;
   }
-#endif
+#endif /* CHECKSUM_CHECK_TCP */
 
   /* Move the payload pointer in the pbuf so that it points to the
      TCP data instead of the TCP header. */
@@ -158,10 +154,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
     /* drop short packets */
     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
     TCP_STATS_INC(tcp.lenerr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
+    goto dropped;
   }
 
   /* Convert fields in TCP header to host byte order. */
@@ -184,10 +177,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
     LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
     LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
     if (pcb->remote_port == tcphdr->src &&
-       pcb->local_port == tcphdr->dest &&
-       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
-       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
-
+        pcb->local_port == tcphdr->dest &&
+        IP_PCB_IPVER_INPUT_MATCH(pcb) &&
+        ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
+        ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
       /* Move this PCB to the front of the list so that subsequent
          lookups will be faster (we exploit locality in TCP segment
          arrivals). */
@@ -209,9 +202,10 @@ tcp_input(struct pbuf *p, struct netif *inp)
     for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
       LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
       if (pcb->remote_port == tcphdr->src &&
-         pcb->local_port == tcphdr->dest &&
-         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
-         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
+          pcb->local_port == tcphdr->dest &&
+          IP_PCB_IPVER_INPUT_MATCH(pcb) &&
+          ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) &&
+          ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) {
         /* We don't really care enough to move this PCB to the front
            of the list since we are not very likely to receive that
            many segments for connections in TIME-WAIT. */
@@ -222,27 +216,36 @@ tcp_input(struct pbuf *p, struct netif *inp)
       }
     }
 
-  /* Finally, if we still did not get a match, we check all PCBs that
-     are LISTENing for incoming connections. */
+    /* Finally, if we still did not get a match, we check all PCBs that
+       are LISTENing for incoming connections. */
     prev = NULL;
     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
       if (lpcb->local_port == tcphdr->dest) {
-#if SO_REUSE
-        if (ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) {
-          /* found an exact match */
-          break;
-        } else if(ip_addr_isany(&(lpcb->local_ip))) {
+#if LWIP_IPV6
+        if (lpcb->accept_any_ip_version) {
           /* found an ANY-match */
+#if SO_REUSE
           lpcb_any = lpcb;
           lpcb_prev = prev;
-        }
 #else /* SO_REUSE */
-        if (ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest)) ||
-            ip_addr_isany(&(lpcb->local_ip))) {
-          /* found a match */
           break;
-        }
 #endif /* SO_REUSE */
+        } else
+#endif /* LWIP_IPV6 */
+        if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) {
+          if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) {
+            /* found an exact match */
+            break;
+          } else if (ipX_addr_isany(ip_current_is_v6(), &lpcb->local_ip)) {
+            /* found an ANY-match */
+#if SO_REUSE
+            lpcb_any = lpcb;
+            lpcb_prev = prev;
+#else /* SO_REUSE */
+            break;
+ #endif /* SO_REUSE */
+          }
+        }
       }
       prev = (struct tcp_pcb *)lpcb;
     }
@@ -255,22 +258,22 @@ tcp_input(struct pbuf *p, struct netif *inp)
     }
 #endif /* SO_REUSE */
     if (lpcb != NULL) {
-        /* Move this PCB to the front of the list so that subsequent
-           lookups will be faster (we exploit locality in TCP segment
-           arrivals). */
-        if (prev != NULL) {
-          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
-                /* our successor is the remainder of the listening list */
-          lpcb->next = tcp_listen_pcbs.listen_pcbs;
-                /* put this listening pcb at the head of the listening list */
-          tcp_listen_pcbs.listen_pcbs = lpcb;
-        }
-      
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
-        tcp_listen_input(lpcb);
-        pbuf_free(p);
-        return;
+      /* Move this PCB to the front of the list so that subsequent
+         lookups will be faster (we exploit locality in TCP segment
+         arrivals). */
+      if (prev != NULL) {
+        ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
+              /* our successor is the remainder of the listening list */
+        lpcb->next = tcp_listen_pcbs.listen_pcbs;
+              /* put this listening pcb at the head of the listening list */
+        tcp_listen_pcbs.listen_pcbs = lpcb;
       }
+    
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
+      tcp_listen_input(lpcb);
+      pbuf_free(p);
+      return;
+    }
   }
 
 #if TCP_INPUT_DEBUG
@@ -291,7 +294,6 @@ tcp_input(struct pbuf *p, struct netif *inp)
     /* Set up a tcp_seg structure. */
     inseg.next = NULL;
     inseg.len = p->tot_len;
-    inseg.dataptr = p->payload;
     inseg.p = p;
     inseg.tcphdr = tcphdr;
 
@@ -305,14 +307,12 @@ tcp_input(struct pbuf *p, struct netif *inp)
       TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
       if (err == ERR_OK) {
         pcb->refused_data = NULL;
-      } else {
+      } else if ((err == ERR_ABRT) || (tcplen > 0)) {
         /* if err == ERR_ABRT, 'pcb' is already deallocated */
-        /* drop incoming packets, because pcb is "full" */
+        /* Drop incoming packets because pcb is "full" (only if the incoming
+           segment contains data). */
         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
-        TCP_STATS_INC(tcp.drop);
-        snmp_inc_tcpinerrs();
-        pbuf_free(p);
-        return;
+        goto dropped;
       }
     }
     tcp_input_pcb = pcb;
@@ -344,8 +344,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
             goto aborted;
           }
         }
-      
+
         if (recv_data != NULL) {
+          LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
           if (pcb->flags & TF_RXCLOSED) {
             /* received data although already closed -> abort (send RST) to
                notify the remote host that not all data has been processed */
@@ -386,14 +387,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
 
         tcp_input_pcb = NULL;
         /* Try to send something out. */
-          tcp_output(pcb);
+        tcp_output(pcb);
 #if TCP_INPUT_DEBUG
 #if TCP_DEBUG
         tcp_debug_print_state(pcb->state);
 #endif /* TCP_DEBUG */
 #endif /* TCP_INPUT_DEBUG */
-        }
       }
+    }
     /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
        Below this line, 'pcb' may not be dereferenced! */
 aborted:
@@ -414,15 +415,19 @@ aborted:
     if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
       TCP_STATS_INC(tcp.proterr);
       TCP_STATS_INC(tcp.drop);
-      tcp_rst(ackno, seqno + tcplen,
-        &(iphdr->dest), &(iphdr->src),
-        tcphdr->dest, tcphdr->src);
+      tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
+        ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
     }
     pbuf_free(p);
   }
 
   LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
   PERF_STOP("tcp_input");
+  return;
+dropped:
+  TCP_STATS_INC(tcp.drop);
+  snmp_inc_tcpinerrs();
+  pbuf_free(p);
 }
 
 /**
@@ -449,9 +454,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
     /* For incoming segments with the ACK flag set, respond with a
        RST. */
     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
-    tcp_rst(ackno + 1, seqno + tcplen,
-      &(iphdr->dest), &(iphdr->src),
-      tcphdr->dest, tcphdr->src);
+    tcp_rst(ackno + 1, seqno + tcplen, ipX_current_dest_addr(),
+      ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
   } else if (flags & TCP_SYN) {
     LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
 #if TCP_LISTEN_BACKLOG
@@ -473,9 +477,12 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
     pcb->accepts_pending++;
 #endif /* TCP_LISTEN_BACKLOG */
     /* Set up the new PCB. */
-    ip_addr_copy(npcb->local_ip, iphdr->dest);
+#if LWIP_IPV6
+    PCB_ISIPV6(npcb) = ip_current_is_v6();
+#endif /* LWIP_IPV6 */
+    ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr());
+    ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr());
     npcb->local_port = pcb->local_port;
-    ip_addr_copy(npcb->remote_ip, iphdr->src);
     npcb->remote_port = tcphdr->src;
     npcb->state = SYN_RCVD;
     npcb->rcv_nxt = seqno + 1;
@@ -496,7 +503,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
     /* Parse any options in the SYN. */
     tcp_parseopt(npcb);
 #if TCP_CALCULATE_EFF_SEND_MSS
-    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
+    npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip,
+      &npcb->remote_ip, PCB_ISIPV6(npcb));
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
 
     snmp_inc_tcppassiveopens();
@@ -538,10 +546,10 @@ tcp_timewait_input(struct tcp_pcb *pcb)
        should be sent in reply */
     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
       /* If the SYN is in the window it is an error, send a reset */
-      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
-        tcphdr->dest, tcphdr->src);
+      tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
+        ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
       return ERR_OK;
-  }
+    }
   } else if (flags & TCP_FIN) {
     /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
          Restart the 2 MSL time-wait timeout.*/
@@ -551,7 +559,7 @@ tcp_timewait_input(struct tcp_pcb *pcb)
   if ((tcplen > 0))  {
     /* Acknowledge data, FIN or out-of-window SYN */
     pcb->flags |= TF_ACK_NOW;
-  return tcp_output(pcb);
+    return tcp_output(pcb);
   }
   return ERR_OK;
 }
@@ -613,7 +621,7 @@ tcp_process(struct tcp_pcb *pcb)
   
   if ((pcb->flags & TF_RXCLOSED) == 0) {
     /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
-  pcb->tmr = tcp_ticks;
+    pcb->tmr = tcp_ticks;
   }
   pcb->keep_cnt_sent = 0;
 
@@ -636,7 +644,8 @@ tcp_process(struct tcp_pcb *pcb)
       pcb->state = ESTABLISHED;
 
 #if TCP_CALCULATE_EFF_SEND_MSS
-      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
+      pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip,
+        PCB_ISIPV6(pcb));
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
 
       /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
@@ -672,8 +681,8 @@ tcp_process(struct tcp_pcb *pcb)
     /* received ACK? possibly a half-open connection */
     else if (flags & TCP_ACK) {
       /* send a RST to bring the other side in a non-synchronized state. */
-      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
-        tcphdr->dest, tcphdr->src);
+      tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
+        ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
     }
     break;
   case SYN_RCVD:
@@ -693,7 +702,7 @@ tcp_process(struct tcp_pcb *pcb)
            * the connection. */
           /* Already aborted? */
           if (err != ERR_ABRT) {
-          tcp_abort(pcb);
+            tcp_abort(pcb);
           }
           return ERR_ABRT;
         }
@@ -715,8 +724,8 @@ tcp_process(struct tcp_pcb *pcb)
         }
       } else {
         /* incorrect ACK number, send RST */
-        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
-                tcphdr->dest, tcphdr->src);
+        tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(),
+          ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6());
       }
     } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
       /* Looks like another copy of the SYN - retransmit our SYN-ACK */
@@ -904,25 +913,25 @@ tcp_receive(struct tcp_pcb *pcb)
       /* Clause 2 */
       if (tcplen == 0) {
         /* Clause 3 */
-      if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
+        if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
           /* Clause 4 */
           if (pcb->rtime >= 0) {
             /* Clause 5 */
             if (pcb->lastack == ackno) {
               found_dupack = 1;
               if (pcb->dupacks + 1 > pcb->dupacks)
-        ++pcb->dupacks;
+                ++pcb->dupacks;
               if (pcb->dupacks > 3) {
-            /* Inflate the congestion window, but not if it means that
-               the value overflows. */
-            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-              pcb->cwnd += pcb->mss;
-            }
+                /* Inflate the congestion window, but not if it means that
+                   the value overflows. */
+                if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
+                  pcb->cwnd += pcb->mss;
+                }
               } else if (pcb->dupacks == 3) {
                 /* Do fast retransmit */
                 tcp_rexmit_fast(pcb);
-          }
-        }
+              }
+            }
           }
         }
       }
@@ -933,7 +942,7 @@ tcp_receive(struct tcp_pcb *pcb)
       }
     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
       /* We come here when the ACK acknowledges new data. */
-      
+
       /* Reset the "IN Fast Retransmit" flag, since we are no longer
          in fast retransmit. Also reset the congestion window to the
          slow start threshold. */
@@ -1018,6 +1027,13 @@ tcp_receive(struct tcp_pcb *pcb)
         pcb->rtime = 0;
 
       pcb->polltmr = 0;
+
+#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
+      if (PCB_ISIPV6(pcb)) {
+        /* Inform neighbor reachability of forward progress. */
+        nd6_reachability_hint(ip6_current_src_addr());
+      }
+#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
     } else {
       /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
       pcb->acked = 0;
@@ -1165,9 +1181,6 @@ tcp_receive(struct tcp_pcb *pcb)
           LWIP_ASSERT("pbuf_header failed", 0);
         }
       }
-      /* KJM following line changed to use p->payload rather than inseg->p->payload
-         to fix bug #9076 */
-      inseg.dataptr = p->payload;
       inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
       inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
     }
@@ -1228,7 +1241,7 @@ tcp_receive(struct tcp_pcb *pcb)
               pcb->ooseq = pcb->ooseq->next;
               tcp_seg_free(old_ooseq);
             }
-            }               
+          }
           else {
             next = pcb->ooseq;
             /* Remove all segments on ooseq that are covered by inseg already.
@@ -1338,6 +1351,13 @@ tcp_receive(struct tcp_pcb *pcb)
         /* Acknowledge the segment(s). */
         tcp_ack(pcb);
 
+#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
+        if (PCB_ISIPV6(pcb)) {
+          /* Inform neighbor reachability of forward progress. */
+          nd6_reachability_hint(ip6_current_src_addr());
+        }
+#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
+
       } else {
         /* We get here if the incoming segment is out-of-sequence. */
         tcp_send_empty_ack(pcb);
@@ -1403,23 +1423,23 @@ tcp_receive(struct tcp_pcb *pcb)
                 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
                   TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
                 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
-                /* The sequence number of the incoming segment is in
-                   between the sequence numbers of the previous and
+                  /* The sequence number of the incoming segment is in
+                     between the sequence numbers of the previous and
                      the next segment on ->ooseq. We trim trim the previous
                      segment, delete next segments that included in received segment
                      and trim received, if needed. */
-                cseg = tcp_seg_copy(&inseg);
-                if (cseg != NULL) {
-                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
-                    /* We need to trim the prev segment. */
-                    prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
-                    pbuf_realloc(prev->p, prev->len);
-                  }
+                  cseg = tcp_seg_copy(&inseg);
+                  if (cseg != NULL) {
+                    if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
+                      /* We need to trim the prev segment. */
+                      prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
+                      pbuf_realloc(prev->p, prev->len);
+                    }
                     prev->next = cseg;
                     tcp_oos_insert_segment(cseg, next);
+                  }
+                  break;
                 }
-                break;
-              }
               }
               /* If the "next" segment is the last segment on the
                  ooseq queue, we add the incoming segment to the end
index a5790bddd6e4c14d94211e3973b737068dd0d1e7..069df8939d71013f1de3990784c322a67916d4bd 100644 (file)
 #include "lwip/def.h"
 #include "lwip/mem.h"
 #include "lwip/memp.h"
-#include "lwip/sys.h"
 #include "lwip/ip_addr.h"
 #include "lwip/netif.h"
 #include "lwip/inet_chksum.h"
 #include "lwip/stats.h"
 #include "lwip/snmp.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
+#if LWIP_TCP_TIMESTAMPS
+#include "lwip/sys.h"
+#endif
 
 #include <string.h>
 
@@ -98,17 +103,17 @@ tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
     LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
                  (p->len >= TCP_HLEN + optlen));
     tcphdr = (struct tcp_hdr *)p->payload;
-  tcphdr->src = htons(pcb->local_port);
-  tcphdr->dest = htons(pcb->remote_port);
-  tcphdr->seqno = seqno_be;
-  tcphdr->ackno = htonl(pcb->rcv_nxt);
+    tcphdr->src = htons(pcb->local_port);
+    tcphdr->dest = htons(pcb->remote_port);
+    tcphdr->seqno = seqno_be;
+    tcphdr->ackno = htonl(pcb->rcv_nxt);
     TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
-  tcphdr->wnd = htons(pcb->rcv_ann_wnd);
-  tcphdr->chksum = 0;
+    tcphdr->wnd = htons(pcb->rcv_ann_wnd);
+    tcphdr->chksum = 0;
     tcphdr->urgp = 0;
 
-  /* If we're sending a packet, update the announced right window edge */
-  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
+    /* If we're sending a packet, update the announced right window edge */
+    pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
   }
   return p;
 }
@@ -142,7 +147,7 @@ tcp_send_fin(struct tcp_pcb *pcb)
  * Create a TCP segment with prefilled header.
  *
  * Called by tcp_write and tcp_enqueue_flags.
- * 
+ *
  * @param pcb Protocol control block for the TCP connection.
  * @param p pbuf that is used to hold the TCP header.
  * @param flags TCP flags for header.
@@ -162,11 +167,10 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
     pbuf_free(p);
     return NULL;
-    }
+  }
   seg->flags = optflags;
   seg->next = NULL;
   seg->p = p;
-  seg->dataptr = p->payload;
   seg->len = p->tot_len - optlen;
 #if TCP_OVERSIZE_DBGCHECK
   seg->oversize_left = 0;
@@ -195,7 +199,7 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
   /* wnd and chksum are set in tcp_output */
   seg->tcphdr->urgp = 0;
   return seg;
-}
+} 
 
 /**
  * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
@@ -381,14 +385,14 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
   err = tcp_write_checks(pcb, len);
   if (err != ERR_OK) {
     return err;
-    }
+  }
   queuelen = pcb->snd_queuelen;
 
 #if LWIP_TCP_TIMESTAMPS
   if ((pcb->flags & TF_TIMESTAMP)) {
     optflags = TF_SEG_OPTS_TS;
     optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
-    }
+  }
 #endif /* LWIP_TCP_TIMESTAMPS */
 
 
@@ -467,14 +471,14 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
       /* Create a pbuf with a copy or reference to seglen bytes. We
        * can use PBUF_RAW here since the data appears in the middle of
        * a segment. A header will never be prepended. */
-    if (apiflags & TCP_WRITE_FLAG_COPY) {
+      if (apiflags & TCP_WRITE_FLAG_COPY) {
         /* Data is copied */
         if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
                       ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
                        seglen));
-        goto memerr;
-      }
+          goto memerr;
+        }
 #if TCP_OVERSIZE_DBGCHECK
         last_unsent->oversize_left = oversize;
 #endif /* TCP_OVERSIZE_DBGCHECK */
@@ -485,10 +489,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
       } else {
         /* Data is not copied */
         if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, 
+          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
                       ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
-        goto memerr;
-      }
+          goto memerr;
+        }
 #if TCP_CHECKSUM_ON_COPY
         /* calculate the checksum of nocopy-data */
         tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
@@ -547,13 +551,13 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
 #endif /* TCP_OVERSIZE */
       if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
-          goto memerr;
-        }
+        goto memerr;
+      }
 #if TCP_CHECKSUM_ON_COPY
       /* calculate the checksum of nocopy-data */
       chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
 #endif /* TCP_CHECKSUM_ON_COPY */
-        /* reference the non-volatile payload data */
+      /* reference the non-volatile payload data */
       p2->payload = (u8_t*)arg + pos;
 
       /* Second, allocate a pbuf for the headers. */
@@ -590,10 +594,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
     seg->chksum_swapped = chksum_swapped;
     seg->flags |= TF_SEG_DATA_CHECKSUMMED;
 #endif /* TCP_CHECKSUM_ON_COPY */
-    /* Fix dataptr for the nocopy case */
-    if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
-      seg->dataptr = (u8_t*)arg + pos;
-    }
 
     /* first segment of to-be-queued data? */
     if (queue == NULL) {
@@ -637,7 +637,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
 #if TCP_OVERSIZE_DBGCHECK
     last_unsent->oversize_left -= oversize_used;
 #endif /* TCP_OVERSIZE_DBGCHECK */
-    }
+  }
   pcb->unsent_oversize = oversize;
 #endif /* TCP_OVERSIZE */
 
@@ -663,10 +663,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
    * is harmless
    */
   if (last_unsent == NULL) {
-      pcb->unsent = queue;
+    pcb->unsent = queue;
   } else {
     last_unsent->next = queue;
-    }
+  }
 
   /*
    * Finally update the pcb state.
@@ -679,7 +679,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
     pcb->snd_queuelen));
   if (pcb->snd_queuelen != 0) {
     LWIP_ASSERT("tcp_write: valid queue length",
-      pcb->unacked != NULL || pcb->unsent != NULL);
+                pcb->unacked != NULL || pcb->unsent != NULL);
   }
 
   /* Set the PSH flag in the last segment that we enqueued. */
@@ -771,8 +771,9 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
   if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
     pcb->flags |= TF_NAGLEMEMERR;
     TCP_STATS_INC(tcp.memerr);
-  return ERR_MEM;
+    return ERR_MEM;
   }
+  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
   LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
 
   LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
@@ -815,7 +816,6 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
   return ERR_OK;
 }
 
-
 #if LWIP_TCP_TIMESTAMPS
 /* Build a timestamp option (12 bytes long) at the specified options pointer)
  *
@@ -845,44 +845,44 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
 
 #if LWIP_TCP_TIMESTAMPS
   if (pcb->flags & TF_TIMESTAMP) {
-      optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
+    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
   }
 #endif
 
   p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
-    if (p == NULL) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
-      return ERR_BUF;
-    }
+  if (p == NULL) {
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
+    return ERR_BUF;
+  }
   tcphdr = (struct tcp_hdr *)p->payload;
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, 
-                ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
-    /* remove ACK flags from the PCB, as we send an empty ACK now */
-    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, 
+              ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
+  /* remove ACK flags from the PCB, as we send an empty ACK now */
+  pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
 
-    /* NB. MSS option is only sent on SYNs, so ignore it here */
+  /* NB. MSS option is only sent on SYNs, so ignore it here */
 #if LWIP_TCP_TIMESTAMPS
-    pcb->ts_lastacksent = pcb->rcv_nxt;
+  pcb->ts_lastacksent = pcb->rcv_nxt;
 
   if (pcb->flags & TF_TIMESTAMP) {
-      tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
+    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
   }
 #endif 
 
 #if CHECKSUM_GEN_TCP
-    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
-          IP_PROTO_TCP, p->tot_len);
+  tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
+    &pcb->local_ip, &pcb->remote_ip);
 #endif
 #if LWIP_NETIF_HWADDRHINT
-    ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-        IP_PROTO_TCP, &(pcb->addr_hint));
+  ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos,
+      IP_PROTO_TCP, &pcb->addr_hint);
 #else /* LWIP_NETIF_HWADDRHINT*/
-    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-        IP_PROTO_TCP);
+  ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos,
+      IP_PROTO_TCP);
 #endif /* LWIP_NETIF_HWADDRHINT*/
-    pbuf_free(p);
+  pbuf_free(p);
 
-    return ERR_OK;
+  return ERR_OK;
 }
 
 /**
@@ -901,6 +901,10 @@ tcp_output(struct tcp_pcb *pcb)
   s16_t i = 0;
 #endif /* TCP_CWND_DEBUG */
 
+  /* pcb->state LISTEN not allowed here */
+  LWIP_ASSERT("don't call tcp_output for listen-pcbs",
+    pcb->state != LISTEN);
+
   /* First, check if we are invoked by the TCP input processing
      code. If so, we do not output anything. Instead, we rely on the
      input processing code to call us when input processing is done
@@ -1050,7 +1054,6 @@ static void
 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
 {
   u16_t len;
-  struct netif *netif;
   u32_t *opts;
 
   /** @bug Exclude retransmitted segments from this count. */
@@ -1067,7 +1070,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
 
   /* Add any requested options.  NB MSS option is only set on SYN
      packets, so ignore it here */
-  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)(seg->tcphdr + 1) % 4) == 0);
+  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
   opts = (u32_t *)(void *)(seg->tcphdr + 1);
   if (seg->flags & TF_SEG_OPTS_MSS) {
     TCP_BUILD_MSS_OPTION(*opts);
@@ -1082,19 +1085,22 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
   }
 #endif
 
+  /* Set retransmission timer running if it is not currently enabled 
+     This must be set before checking the route. */
+  if (pcb->rtime == -1) {
+    pcb->rtime = 0;
+  }
+
   /* If we don't have a local IP address, we get one by
      calling ip_route(). */
-  if (ip_addr_isany(&(pcb->local_ip))) {
-    netif = ip_route(&(pcb->remote_ip));
-    if (netif == NULL) {
+  if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
+    struct netif *netif;
+    ipX_addr_t *local_ip;
+    ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip);
+    if ((netif == NULL) || (local_ip == NULL)) {
       return;
     }
-    ip_addr_copy(pcb->local_ip, netif->ip_addr);
-  }
-
-  /* Set retransmission timer running if it is not currently enabled */
-  if(pcb->rtime == -1) {
-    pcb->rtime = 0;
+    ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip);
   }
 
   if (pcb->rttest == 0) {
@@ -1115,14 +1121,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
   seg->p->payload = seg->tcphdr;
 
   seg->tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
 #if TCP_CHECKSUM_ON_COPY
   {
     u32_t acc;
 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
-    u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
-             &(pcb->remote_ip),
-             IP_PROTO_TCP, seg->p->tot_len);
+    u16_t chksum_slow = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
+      seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
     if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
       LWIP_ASSERT("data included but not checksummed",
@@ -1130,9 +1134,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
     }
 
     /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
-    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
-             &(pcb->remote_ip),
-             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
+    acc = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
+      seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip);
     /* add payload checksum */
     if (seg->chksum_swapped) {
       seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
@@ -1150,19 +1153,19 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
   }
 #else /* TCP_CHECKSUM_ON_COPY */
-  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
-         &(pcb->remote_ip),
-         IP_PROTO_TCP, seg->p->tot_len);
-#endif /* TCP_CHECKSUM_ON_COPY */
+#if CHECKSUM_GEN_TCP
+  seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP,
+    seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
 #endif /* CHECKSUM_GEN_TCP */
+#endif /* TCP_CHECKSUM_ON_COPY */
   TCP_STATS_INC(tcp.xmit);
 
 #if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IP_PROTO_TCP, &(pcb->addr_hint));
+  ipX_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip,
+    pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint);
 #else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IP_PROTO_TCP);
+  ipX_output(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
+    pcb->tos, IP_PROTO_TCP);
 #endif /* LWIP_NETIF_HWADDRHINT*/
 }
 
@@ -1187,9 +1190,13 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
  * @param remote_port the remote TCP port to send the segment to
  */
 void
-tcp_rst(u32_t seqno, u32_t ackno,
-  ip_addr_t *local_ip, ip_addr_t *remote_ip,
-  u16_t local_port, u16_t remote_port)
+tcp_rst_impl(u32_t seqno, u32_t ackno,
+  ipX_addr_t *local_ip, ipX_addr_t *remote_ip,
+  u16_t local_port, u16_t remote_port
+#if LWIP_IPV6
+  , u8_t isipv6
+#endif /* LWIP_IPV6 */
+  )
 {
   struct pbuf *p;
   struct tcp_hdr *tcphdr;
@@ -1211,14 +1218,15 @@ tcp_rst(u32_t seqno, u32_t ackno,
   tcphdr->chksum = 0;
   tcphdr->urgp = 0;
 
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
-              IP_PROTO_TCP, p->tot_len);
-#endif
   TCP_STATS_INC(tcp.xmit);
   snmp_inc_tcpoutrsts();
-   /* Send output with hardcoded TTL since we have no access to the pcb */
-  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
+
+#if CHECKSUM_GEN_TCP
+  tcphdr->chksum = ipX_chksum_pseudo(isipv6, p, IP_PROTO_TCP, p->tot_len,
+                                     local_ip, remote_ip);
+#endif
+  /* Send output with hardcoded TTL/HL since we have no access to the pcb */
+  ipX_output(isipv6, p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
   pbuf_free(p);
   LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
 }
@@ -1354,9 +1362,9 @@ tcp_keepalive(struct tcp_pcb *pcb)
   struct pbuf *p;
   struct tcp_hdr *tcphdr;
 
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-                          ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
-                          ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to "));
+  ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
+  LWIP_DEBUGF(TCP_DEBUG, ("\n"));
 
   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", 
                           tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
@@ -1369,18 +1377,17 @@ tcp_keepalive(struct tcp_pcb *pcb)
   }
   tcphdr = (struct tcp_hdr *)p->payload;
 
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
-                                      IP_PROTO_TCP, p->tot_len);
-#endif
+  tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
+      &pcb->local_ip, &pcb->remote_ip);
   TCP_STATS_INC(tcp.xmit);
 
   /* Send output to IP */
 #if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
-    &(pcb->addr_hint));
+  ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip,
+    pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint);
 #else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
+  ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
+    0, IP_PROTO_TCP);
 #endif /* LWIP_NETIF_HWADDRHINT*/
 
   pbuf_free(p);
@@ -1407,11 +1414,9 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
   u16_t len;
   u8_t is_fin;
 
-  LWIP_DEBUGF(TCP_DEBUG, 
-              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
-               U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-               ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
-               ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
+  ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip);
+  LWIP_DEBUGF(TCP_DEBUG, ("\n"));
 
   LWIP_DEBUGF(TCP_DEBUG, 
               ("tcp_zero_window_probe: tcp_ticks %"U32_F
@@ -1430,7 +1435,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
   is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
   /* we want to send one seqno: either FIN or data (no options) */
   len = is_fin ? 0 : 1;
-   
+
   p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
   if(p == NULL) {
     LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
@@ -1443,21 +1448,23 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
     TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
   } else {
     /* Data segment, copy in one byte from the head of the unacked queue */
-    *((char *)p->payload + TCP_HLEN) = *(char *)seg->dataptr;
+    struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
+    char *d = ((char *)p->payload + TCP_HLEN);
+    pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
   }
 
 #if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
-                                      IP_PROTO_TCP, p->tot_len);
+  tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len,
+      &pcb->local_ip, &pcb->remote_ip);
 #endif
   TCP_STATS_INC(tcp.xmit);
 
   /* Send output to IP */
 #if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
-    &(pcb->addr_hint));
+  ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
+    0, IP_PROTO_TCP, &pcb->addr_hint);
 #else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
+  ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
 #endif /* LWIP_NETIF_HWADDRHINT*/
 
   pbuf_free(p);
index 0dba927246b57c820d35c2b0eea12810f1d97fd6..3c4f8d1d84ccb8ddb918a63cbe2fbb8098c742c7 100644 (file)
 #include "lwip/opt.h"
 
 #include "lwip/timers.h"
+#include "lwip/tcp_impl.h"
+
+#if LWIP_TIMERS
+
 #include "lwip/def.h"
 #include "lwip/memp.h"
 #include "lwip/tcpip.h"
 
-#include "lwip/tcp_impl.h"
 #include "lwip/ip_frag.h"
 #include "netif/etharp.h"
 #include "lwip/dhcp.h"
 #include "lwip/autoip.h"
 #include "lwip/igmp.h"
 #include "lwip/dns.h"
-
+#include "lwip/nd6.h"
+#include "lwip/ip6_frag.h"
+#include "lwip/mld6.h"
+#include "lwip/sys.h"
+#include "lwip/pbuf.h"
 
 /** The one and only timeout list */
 static struct sys_timeo *next_timeout;
@@ -214,6 +221,54 @@ dns_timer(void *arg)
 }
 #endif /* LWIP_DNS */
 
+#if LWIP_IPV6
+/**
+ * Timer callback function that calls nd6_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+nd6_timer(void *arg)
+{
+  LWIP_UNUSED_ARG(arg);
+  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
+  nd6_tmr();
+  sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
+}
+
+#if LWIP_IPV6_REASS
+/**
+ * Timer callback function that calls ip6_reass_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+ip6_reass_timer(void *arg)
+{
+  LWIP_UNUSED_ARG(arg);
+  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
+  ip6_reass_tmr();
+  sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
+}
+#endif /* LWIP_IPV6_REASS */
+
+#if LWIP_IPV6_MLD
+/**
+ * Timer callback function that calls mld6_tmr() and reschedules itself.
+ *
+ * @param arg unused argument
+ */
+static void
+mld6_timer(void *arg)
+{
+  LWIP_UNUSED_ARG(arg);
+  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
+  mld6_tmr();
+  sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
+}
+#endif /* LWIP_IPV6_MLD */
+#endif /* LWIP_IPV6 */
+
 /** Initialize this module */
 void sys_timeouts_init(void)
 {
@@ -236,6 +291,15 @@ void sys_timeouts_init(void)
 #if LWIP_DNS
   sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
 #endif /* LWIP_DNS */
+#if LWIP_IPV6
+  sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
+#if LWIP_IPV6_REASS
+  sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
+#endif /* LWIP_IPV6_REASS */
+#if LWIP_IPV6_MLD
+  sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
+#endif /* LWIP_IPV6_MLD */
+#endif /* LWIP_IPV6 */
 
 #if NO_SYS
   /* Initialise timestamp for sys_check_timeouts */
@@ -250,15 +314,15 @@ void sys_timeouts_init(void)
  * - by calling sys_check_timeouts() (NO_SYS==1 only)
  *
  * @param msecs time in milliseconds after that the timer should expire
- * @param h callback function to call when msecs have elapsed
+ * @param handler callback function to call when msecs have elapsed
  * @param arg argument to pass to the callback function
  */
 #if LWIP_DEBUG_TIMERNAMES
 void
-sys_timeout_debug(u32_t msecs, sys_timeout_handler h, void *arg, const char* handler_name)
+sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
 #else /* LWIP_DEBUG_TIMERNAMES */
 void
-sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
+sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
 #endif /* LWIP_DEBUG_TIMERNAMES */
 {
   struct sys_timeo *timeout, *t;
@@ -269,19 +333,13 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
     return;
   }
   timeout->next = NULL;
-  timeout->h = h;
+  timeout->h = handler;
   timeout->arg = arg;
   timeout->time = msecs;
 #if LWIP_DEBUG_TIMERNAMES
   timeout->handler_name = handler_name;
-#endif /* LWIP_DEBUG_TIMERNAMES */
-
-#if LWIP_DEBUG_TIMERNAMES
-  LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p name=%s\n",
-    (void *)timeout, msecs, *(void**)&h, (void *)arg, handler_name));
-#else /* LWIP_DEBUG_TIMERNAMES */
-  LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
-    (void *)timeout, msecs, *(void**)&h, (void *)arg));
+  LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
+    (void *)timeout, msecs, handler_name, (void *)arg));
 #endif /* LWIP_DEBUG_TIMERNAMES */
 
   if (next_timeout == NULL) {
@@ -313,13 +371,13 @@ sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
  * entry, even though the timeout has not triggered yet.
  *
  * @note This function only works as expected if there is only one timeout
- * calling 'h' in the list of timeouts.
+ * calling 'handler' in the list of timeouts.
  *
- * @param h callback function that would be called by the timeout
- * @param arg callback argument that would be passed to h
+ * @param handler callback function that would be called by the timeout
+ * @param arg callback argument that would be passed to handler
 */
 void
-sys_untimeout(sys_timeout_handler h, void *arg)
+sys_untimeout(sys_timeout_handler handler, void *arg)
 {
   struct sys_timeo *prev_t, *t;
 
@@ -328,7 +386,7 @@ sys_untimeout(sys_timeout_handler h, void *arg)
   }
 
   for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
-    if ((t->h == h) && (t->arg == arg)) {
+    if ((t->h == handler) && (t->arg == arg)) {
       /* We have a match */
       /* Unlink from previous in list */
       if (prev_t == NULL) {
@@ -360,13 +418,10 @@ sys_check_timeouts(void)
 {
   struct sys_timeo *tmptimeout;
   u32_t diff;
-  sys_timeout_handler h;
+  sys_timeout_handler handler;
   void *arg;
   int had_one;
   u32_t now;
-#if LWIP_DEBUG_TIMERNAMES
-  const char *handler_name;
-#endif /* LWIP_DEBUG_TIMERNAMES */
 
   now = sys_now();
   if (next_timeout) {
@@ -374,6 +429,9 @@ sys_check_timeouts(void)
     diff = LWIP_U32_DIFF(now, timeouts_last_time);
     do
     {
+#if PBUF_POOL_FREE_OOSEQ
+      PBUF_CHECK_FREE_OOSEQ();
+#endif /* PBUF_POOL_FREE_OOSEQ */
       had_one = 0;
       tmptimeout = next_timeout;
       if (tmptimeout->time <= diff) {
@@ -382,19 +440,17 @@ sys_check_timeouts(void)
         timeouts_last_time = now;
         diff -= tmptimeout->time;
         next_timeout = tmptimeout->next;
-        h   = tmptimeout->h;
+        handler = tmptimeout->h;
         arg = tmptimeout->arg;
 #if LWIP_DEBUG_TIMERNAMES
-        handler_name = tmptimeout->handler_name;
+        if (handler != NULL) {
+          LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
+            tmptimeout->handler_name, arg));
+        }
 #endif /* LWIP_DEBUG_TIMERNAMES */
         memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-        if (h != NULL) {
-#if LWIP_DEBUG_TIMERNAMES
-          LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%p(%p) (%s)\n", *(void**)&h, arg, handler_name));
-#else /* LWIP_DEBUG_TIMERNAMES */
-          LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%p(%p)\n", *(void**)&h, arg));
-#endif /* LWIP_DEBUG_TIMERNAMES */
-          h(arg);
+        if (handler != NULL) {
+          handler(arg);
         }
       }
     /* repeat until all expired timers have been called */
@@ -427,11 +483,8 @@ sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
 {
   u32_t time_needed;
   struct sys_timeo *tmptimeout;
-  sys_timeout_handler h;
+  sys_timeout_handler handler;
   void *arg;
-#if LWIP_DEBUG_TIMERNAMES
-  const char *handler_name;
-#endif /* LWIP_DEBUG_TIMERNAMES */
 
  again:
   if (!next_timeout) {
@@ -449,22 +502,20 @@ sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
          deallocate the memory allocated for the timeout. */
       tmptimeout = next_timeout;
       next_timeout = tmptimeout->next;
-      h   = tmptimeout->h;
+      handler = tmptimeout->h;
       arg = tmptimeout->arg;
 #if LWIP_DEBUG_TIMERNAMES
-      handler_name = tmptimeout->handler_name;
+      if (handler != NULL) {
+        LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
+          tmptimeout->handler_name, arg));
+      }
 #endif /* LWIP_DEBUG_TIMERNAMES */
       memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-      if (h != NULL) {
-#if LWIP_DEBUG_TIMERNAMES
-        LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%p(%p) (%s)\n", *(void**)&h, arg, handler_name));
-#else /* LWIP_DEBUG_TIMERNAMES */
-        LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%p(%p)\n", *(void**)&h, arg));
-#endif /* LWIP_DEBUG_TIMERNAMES */
+      if (handler != NULL) {
         /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
            timeout handler function. */
         LOCK_TCPIP_CORE();
-        h(arg);
+        handler(arg);
         UNLOCK_TCPIP_CORE();
       }
       LWIP_TCPIP_THREAD_ALIVE();
@@ -485,3 +536,11 @@ sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
 }
 
 #endif /* NO_SYS */
+
+#else /* LWIP_TIMERS */
+/* Satisfy the TCP code which calls this function */
+void
+tcp_timer_needed(void)
+{
+}
+#endif /* LWIP_TIMERS */
index 0f1562faf85b6167e2a0c05d833435f0ac67dea5..f948d1e189afe2718bcd66b8f12c309100b30a2b 100644 (file)
 #include "lwip/memp.h"
 #include "lwip/inet_chksum.h"
 #include "lwip/ip_addr.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
 #include "lwip/netif.h"
 #include "lwip/icmp.h"
+#include "lwip/icmp6.h"
 #include "lwip/stats.h"
 #include "lwip/snmp.h"
 #include "arch/perf.h"
@@ -76,7 +80,7 @@ struct udp_pcb *udp_pcbs;
  * recv function. If no pcb is found or the datagram is incorrect, the
  * pbuf is freed.
  *
- * @param p pbuf to be demultiplexed to a UDP PCB.
+ * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header)
  * @param inp network interface on which the datagram was received.
  *
  */
@@ -86,20 +90,17 @@ udp_input(struct pbuf *p, struct netif *inp)
   struct udp_hdr *udphdr;
   struct udp_pcb *pcb, *prev;
   struct udp_pcb *uncon_pcb;
-  struct ip_hdr *iphdr;
   u16_t src, dest;
   u8_t local_match;
   u8_t broadcast;
+  u8_t for_us;
 
   PERF_START;
 
   UDP_STATS_INC(udp.recv);
 
-  iphdr = (struct ip_hdr *)p->payload;
-
-  /* Check minimum length (IP header + UDP header)
-   * and move payload pointer to UDP header */
-  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
+  /* Check minimum length (UDP header) */
+  if (p->len < UDP_HLEN) {
     /* drop short packets */
     LWIP_DEBUGF(UDP_DEBUG,
                 ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
@@ -113,7 +114,11 @@ udp_input(struct pbuf *p, struct netif *inp)
   udphdr = (struct udp_hdr *)p->payload;
 
   /* is broadcast packet ? */
-  broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp);
+#if LWIP_IPV6
+  broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp);
+#else /* LWIP_IPV6 */
+  broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp);
+#endif /* LWIP_IPV6 */
 
   LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
 
@@ -124,13 +129,11 @@ udp_input(struct pbuf *p, struct netif *inp)
   udp_debug_print(udphdr);
 
   /* print the UDP source and destination */
-  LWIP_DEBUGF(UDP_DEBUG,
-              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
-               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
-               ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
-               ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
-               ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
-               ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
+  LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
+  ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr());
+  LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
+  ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr());
+  LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
 
 #if LWIP_DHCP
   pcb = NULL;
@@ -142,9 +145,10 @@ udp_input(struct pbuf *p, struct netif *inp)
       if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
         /* accept the packe if 
            (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
-           - inp->dhcp->pcb->remote == ANY or iphdr->src */
-        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
-           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
+           - inp->dhcp->pcb->remote == ANY or iphdr->src
+           (no need to check for IPv6 since the dhcp struct always uses IPv4) */
+        if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) ||
+            ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) {
           pcb = inp->dhcp->pcb;
         }
       }
@@ -162,25 +166,35 @@ udp_input(struct pbuf *p, struct netif *inp)
     for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
       local_match = 0;
       /* print the PCB local and remote address */
-      LWIP_DEBUGF(UDP_DEBUG,
-                  ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
-                   "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
-                   ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
-                   ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
-                   ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
-                   ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
+      LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));
+      ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip);
+      LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
+      ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip);
+      LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));
 
       /* compare PCB local addr+port to UDP destination addr+port */
       if ((pcb->local_port == dest) &&
-          ((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
-           ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
+#if LWIP_IPV6
+          ((PCB_ISIPV6(pcb) && (ip_current_is_v6()) &&
+            (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) ||
+#if LWIP_IPV6_MLD
+            ip6_addr_ismulticast(ip6_current_dest_addr()) ||
+#endif /* LWIP_IPV6_MLD */
+            ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) ||
+           (!PCB_ISIPV6(pcb) &&
+            (ip_current_header() != NULL) &&
+#else /* LWIP_IPV6 */
+           ((
+#endif /* LWIP_IPV6 */
+            ((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) ||
+            ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) ||
 #if LWIP_IGMP
-           ip_addr_ismulticast(&(iphdr->dest)) ||
+            ip_addr_ismulticast(ip_current_dest_addr()) ||
 #endif /* LWIP_IGMP */
 #if IP_SOF_BROADCAST_RECV
-           (broadcast && (pcb->so_options & SOF_BROADCAST)))) {
+            (broadcast && (pcb->so_options & SOF_BROADCAST)))))) {
 #else  /* IP_SOF_BROADCAST_RECV */
-           (broadcast))) {
+            (broadcast))))) {
 #endif /* IP_SOF_BROADCAST_RECV */
         local_match = 1;
         if ((uncon_pcb == NULL) && 
@@ -191,9 +205,9 @@ udp_input(struct pbuf *p, struct netif *inp)
       }
       /* compare PCB remote addr+port to UDP source addr+port */
       if ((local_match != 0) &&
-          (pcb->remote_port == src) &&
-          (ip_addr_isany(&pcb->remote_ip) ||
-           ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
+          (pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
+            (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) ||
+              ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) {
         /* the first fully matching PCB */
         if (prev != NULL) {
           /* move the pcb to the front of udp_pcbs so that is
@@ -215,12 +229,24 @@ udp_input(struct pbuf *p, struct netif *inp)
   }
 
   /* Check checksum if this is a match or if it was directed at us. */
-  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
+  if (pcb != NULL) {
+    for_us = 1;
+  } else {
+#if LWIP_IPV6
+    if (ip_current_is_v6()) {
+      for_us = netif_matches_ip6_addr(inp, ip6_current_dest_addr());
+    } else
+#endif /* LWIP_IPV6 */
+    {
+      for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr());
+    }
+  }
+  if (for_us) {
     LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
+#if CHECKSUM_CHECK_UDP
 #if LWIP_UDPLITE
-    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
+    if (ip_current_header_proto() == IP_PROTO_UDPLITE) {
       /* Do the UDP Lite checksum */
-#if CHECKSUM_CHECK_UDP
       u16_t chklen = ntohs(udphdr->len);
       if (chklen < sizeof(struct udp_hdr)) {
         if (chklen == 0) {
@@ -230,42 +256,26 @@ udp_input(struct pbuf *p, struct netif *inp)
         } else {
           /* At least the UDP-Lite header must be covered by the
              checksum! (Again, see RFC 3828 chap. 3.1) */
-          UDP_STATS_INC(udp.chkerr);
-          UDP_STATS_INC(udp.drop);
-          snmp_inc_udpinerrors();
-          pbuf_free(p);
-          goto end;
+          goto chkerr;
         }
       }
-      if (inet_chksum_pseudo_partial(p, &iphdr->src, &iphdr->dest,
-                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
-       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
-                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
-        UDP_STATS_INC(udp.chkerr);
-        UDP_STATS_INC(udp.drop);
-        snmp_inc_udpinerrors();
-        pbuf_free(p);
-        goto end;
+      if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE,
+                   p->tot_len, chklen,
+                   ipX_current_src_addr(), ipX_current_dest_addr()) != 0) {
+        goto chkerr;
       }
-#endif /* CHECKSUM_CHECK_UDP */
     } else
 #endif /* LWIP_UDPLITE */
     {
-#if CHECKSUM_CHECK_UDP
       if (udphdr->chksum != 0) {
-        if (inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest,
-                               IP_PROTO_UDP, p->tot_len) != 0) {
-          LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
-                      ("udp_input: UDP datagram discarded due to failing checksum\n"));
-          UDP_STATS_INC(udp.chkerr);
-          UDP_STATS_INC(udp.drop);
-          snmp_inc_udpinerrors();
-          pbuf_free(p);
-          goto end;
+        if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len,
+                              ipX_current_src_addr(),
+                              ipX_current_dest_addr()) != 0) {
+          goto chkerr;
         }
       }
-#endif /* CHECKSUM_CHECK_UDP */
     }
+#endif /* CHECKSUM_CHECK_UDP */
     if(pbuf_header(p, -UDP_HLEN)) {
       /* Can we cope with this failing? Just assert for now */
       LWIP_ASSERT("pbuf_header failed\n", 0);
@@ -277,32 +287,45 @@ udp_input(struct pbuf *p, struct netif *inp)
     if (pcb != NULL) {
       snmp_inc_udpindatagrams();
 #if SO_REUSE && SO_REUSE_RXTOALL
-      if ((broadcast || ip_addr_ismulticast(&iphdr->dest)) &&
+      if ((broadcast ||
+#if LWIP_IPV6
+          ip6_addr_ismulticast(ip6_current_dest_addr()) ||
+#endif /* LWIP_IPV6 */
+           ip_addr_ismulticast(ip_current_dest_addr())) &&
           ((pcb->so_options & SOF_REUSEADDR) != 0)) {
         /* pass broadcast- or multicast packets to all multicast pcbs
            if SOF_REUSEADDR is set on the first match */
         struct udp_pcb *mpcb;
         u8_t p_header_changed = 0;
+        s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN);
         for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
           if (mpcb != pcb) {
             /* compare PCB local addr+port to UDP destination addr+port */
             if ((mpcb->local_port == dest) &&
-                ((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
-                 ip_addr_cmp(&(mpcb->local_ip), &(iphdr->dest)) ||
+#if LWIP_IPV6
+                ((PCB_ISIPV6(mpcb) &&
+                  (ip6_addr_ismulticast(ip6_current_dest_addr()) ||
+                   ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) ||
+                 (!PCB_ISIPV6(mpcb) &&
+#else /* LWIP_IPV6 */
+                ((
+#endif /* LWIP_IPV6 */
+                  ((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) ||
+                   ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) ||
 #if LWIP_IGMP
-                 ip_addr_ismulticast(&(iphdr->dest)) ||
+                   ip_addr_ismulticast(ip_current_dest_addr()) ||
 #endif /* LWIP_IGMP */
 #if IP_SOF_BROADCAST_RECV
-                 (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
+                   (broadcast && (mpcb->so_options & SOF_BROADCAST)))))) {
 #else  /* IP_SOF_BROADCAST_RECV */
-                 (broadcast))) {
+                   (broadcast))))) {
 #endif /* IP_SOF_BROADCAST_RECV */
               /* pass a copy of the packet to all local matches */
-              if (mpcb->recv != NULL) {
+              if (mpcb->recv.ip4 != NULL) {
                 struct pbuf *q;
                 /* for that, move payload to IP header again */
                 if (p_header_changed == 0) {
-                  pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
+                  pbuf_header(p, hdrs_len);
                   p_header_changed = 1;
                 }
                 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
@@ -310,9 +333,16 @@ udp_input(struct pbuf *p, struct netif *inp)
                   err_t err = pbuf_copy(q, p);
                   if (err == ERR_OK) {
                     /* move payload to UDP data */
-                    struct ip_hdr *q_iphdr = (struct ip_hdr *)q->payload;
-                    pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
-                    mpcb->recv(mpcb->recv_arg, mpcb, q, &q_iphdr->src, src);
+                    pbuf_header(q, -hdrs_len);
+#if LWIP_IPV6
+                    if (PCB_ISIPV6(mpcb)) {
+                      mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src);
+                    }
+                    else
+#endif /* LWIP_IPV6 */
+                    {
+                      mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
+                    }
                   }
                 }
               }
@@ -321,14 +351,22 @@ udp_input(struct pbuf *p, struct netif *inp)
         }
         if (p_header_changed) {
           /* and move payload to UDP data again */
-          pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
+          pbuf_header(p, -hdrs_len);
         }
       }
 #endif /* SO_REUSE && SO_REUSE_RXTOALL */
       /* callback */
-      if (pcb->recv != NULL) {
+      if (pcb->recv.ip4 != NULL) {
         /* now the recv function is responsible for freeing p */
-        pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src);
+#if LWIP_IPV6
+        if (PCB_ISIPV6(pcb)) {
+          pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src);
+        }
+        else
+#endif /* LWIP_IPV6 */
+        {
+          pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
+        }
       } else {
         /* no recv function registered? then we have to free the pbuf! */
         pbuf_free(p);
@@ -337,17 +375,19 @@ udp_input(struct pbuf *p, struct netif *inp)
     } else {
       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
 
-#if LWIP_ICMP
+#if LWIP_ICMP || LWIP_ICMP6
       /* No match was found, send ICMP destination port unreachable unless
          destination address was broadcast/multicast. */
       if (!broadcast &&
-          !ip_addr_ismulticast(&iphdr->dest)) {
+#if LWIP_IPV6
+          !ip6_addr_ismulticast(ip6_current_dest_addr()) &&
+#endif /* LWIP_IPV6 */
+          !ip_addr_ismulticast(ip_current_dest_addr())) {
         /* move payload pointer back to ip header */
-        pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
-        LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
-        icmp_dest_unreach(p, ICMP_DUR_PORT);
+        pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN);
+        icmp_port_unreach(ip_current_is_v6(), p);
       }
-#endif /* LWIP_ICMP */
+#endif /* LWIP_ICMP || LWIP_ICMP6 */
       UDP_STATS_INC(udp.proterr);
       UDP_STATS_INC(udp.drop);
       snmp_inc_udpnoports();
@@ -358,6 +398,15 @@ udp_input(struct pbuf *p, struct netif *inp)
   }
 end:
   PERF_STOP("udp_input");
+  return;
+chkerr:
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
+              ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n"));
+  UDP_STATS_INC(udp.chkerr);
+  UDP_STATS_INC(udp.drop);
+  snmp_inc_udpinerrors();
+  pbuf_free(p);
+  PERF_STOP("udp_input");
 }
 
 /**
@@ -382,7 +431,7 @@ err_t
 udp_send(struct udp_pcb *pcb, struct pbuf *p)
 {
   /* send to the packet using remote ip and port stored in the pcb */
-  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
+  return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port);
 }
 
 #if LWIP_CHECKSUM_ON_COPY
@@ -393,7 +442,7 @@ udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
                 u8_t have_chksum, u16_t chksum)
 {
   /* send to the packet using remote ip and port stored in the pcb */
-  return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
+  return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port,
     have_chksum, chksum);
 }
 #endif /* LWIP_CHECKSUM_ON_COPY */
@@ -430,20 +479,34 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
 {
 #endif /* LWIP_CHECKSUM_ON_COPY */
   struct netif *netif;
+  ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip);
 
   LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
 
-  /* find the outgoing network interface for this packet */
+#if LWIP_IPV6 || LWIP_IGMP
+  if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) {
+    /* For multicast, find a netif based on source address. */
+#if LWIP_IPV6
+    if (PCB_ISIPV6(pcb)) {
+      dst_ip_route = &pcb->local_ip;
+    } else
+#endif /* LWIP_IPV6 */
+    {
 #if LWIP_IGMP
-  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
-#else
-  netif = ip_route(dst_ip);
+      dst_ip_route = ip_2_ipX(&pcb->multicast_ip);
 #endif /* LWIP_IGMP */
+    }
+  }
+#endif /* LWIP_IPV6 || LWIP_IGMP */
+
+  /* find the outgoing network interface for this packet */
+  netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route);
 
   /* no outgoing network interface could be found? */
   if (netif == NULL) {
-    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
-      ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
+    ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip));
+    LWIP_DEBUGF(UDP_DEBUG, ("\n"));
     UDP_STATS_INC(udp.rterr);
     return ERR_RTE;
   }
@@ -492,10 +555,15 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
   ip_addr_t *src_ip;
   err_t err;
   struct pbuf *q; /* q will be sent down the stack */
+  u8_t ip_proto;
 
 #if IP_SOF_BROADCAST
   /* broadcast filter? */
-  if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
+  if ( ((pcb->so_options & SOF_BROADCAST) == 0) &&
+#if LWIP_IPV6
+      !PCB_ISIPV6(pcb) &&
+#endif /* LWIP_IPV6 */
+      ip_addr_isbroadcast(dst_ip, netif) ) {
     LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
       ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
     return ERR_VAL;
@@ -505,7 +573,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
   /* if the PCB is not yet bound to a port, bind it here */
   if (pcb->local_port == 0) {
     LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
-    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
+    err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
     if (err != ERR_OK) {
       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
       return err;
@@ -521,8 +589,10 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
       return ERR_MEM;
     }
-    /* chain header q in front of given pbuf p */
-    pbuf_chain(q, p);
+    if (p->tot_len != 0) {
+      /* chain header q in front of given pbuf p (only if p contains data) */
+      pbuf_chain(q, p);
+    }
     /* first pbuf q points to header pbuf */
     LWIP_DEBUGF(UDP_DEBUG,
                 ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
@@ -541,14 +611,62 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
   /* in UDP, 0 checksum means 'no checksum' */
   udphdr->chksum = 0x0000; 
 
+  /* Multicast Loop? */
+#if LWIP_IGMP
+  if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) &&
+#if LWIP_IPV6
+      (
+#if LWIP_IPV6_MLD
+       (PCB_ISIPV6(pcb) &&
+        ip6_addr_ismulticast(ip_2_ip6(dst_ip))) ||
+#endif /* LWIP_IPV6_MLD */
+       (!PCB_ISIPV6(pcb) &&
+#else /* LWIP_IPV6 */
+      ((
+#endif /* LWIP_IPV6 */
+        ip_addr_ismulticast(dst_ip)))) {
+    q->flags |= PBUF_FLAG_MCASTLOOP;
+  }
+#endif /* LWIP_IGMP */
+
+
   /* PCB local address is IP_ANY_ADDR? */
-  if (ip_addr_isany(&pcb->local_ip)) {
+#if LWIP_IPV6
+  if (PCB_ISIPV6(pcb)) {
+    if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) {
+      src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip)));
+      if (src_ip == NULL) {
+        /* No suitable source address was found. */
+        if (q != p) {
+          /* free the header pbuf */
+          pbuf_free(q);
+          /* p is still referenced by the caller, and will live on */
+        }
+        return ERR_RTE;
+      }
+    } else {
+      /* use UDP PCB local IPv6 address as source address, if still valid. */
+      if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) {
+        /* Address isn't valid anymore. */
+        if (q != p) {
+          /* free the header pbuf */
+          pbuf_free(q);
+          /* p is still referenced by the caller, and will live on */
+        }
+        return ERR_RTE;
+      }
+      src_ip = ipX_2_ip(&pcb->local_ip);
+    }
+  }
+  else
+#endif /* LWIP_IPV6 */
+  if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) {
     /* use outgoing network interface IP address as source address */
     src_ip = &(netif->ip_addr);
   } else {
     /* check if UDP PCB local IP address is correct
      * this could be an old address if netif->ip_addr has changed */
-    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
+    if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) {
       /* local_ip doesn't match, drop the packet */
       if (q != p) {
         /* free the header pbuf */
@@ -559,7 +677,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
       return ERR_VAL;
     }
     /* use UDP PCB local IP address as source address */
-    src_ip = &(pcb->local_ip);
+    src_ip = ipX_2_ip(&(pcb->local_ip));
   }
 
   LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
@@ -587,33 +705,28 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
     udphdr->len = htons(chklen_hdr);
     /* calculate checksum */
 #if CHECKSUM_GEN_UDP
-    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
-      IP_PROTO_UDPLITE, q->tot_len,
-#if !LWIP_CHECKSUM_ON_COPY
-      chklen);
-#else /* !LWIP_CHECKSUM_ON_COPY */
-      (have_chksum ? UDP_HLEN : chklen));
+#if LWIP_CHECKSUM_ON_COPY
+    if (have_chksum) {
+      chklen = UDP_HLEN;
+    }
+#endif /* LWIP_CHECKSUM_ON_COPY */
+    udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE,
+      q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
+#if LWIP_CHECKSUM_ON_COPY
     if (have_chksum) {
       u32_t acc;
       acc = udphdr->chksum + (u16_t)~(chksum);
       udphdr->chksum = FOLD_U32T(acc);
     }
-#endif /* !LWIP_CHECKSUM_ON_COPY */
+#endif /* LWIP_CHECKSUM_ON_COPY */
 
     /* chksum zero must become 0xffff, as zero means 'no checksum' */
     if (udphdr->chksum == 0x0000) {
       udphdr->chksum = 0xffff;
     }
 #endif /* CHECKSUM_GEN_UDP */
-    /* output to IP */
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
-#if LWIP_NETIF_HWADDRHINT
-    netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
-#if LWIP_NETIF_HWADDRHINT
-    netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
+
+    ip_proto = IP_PROTO_UDPLITE;
   } else
 #endif /* LWIP_UDPLITE */
   {      /* UDP */
@@ -621,39 +734,40 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
     udphdr->len = htons(q->tot_len);
     /* calculate checksum */
 #if CHECKSUM_GEN_UDP
-    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
+    /* Checksum is mandatory over IPv6. */
+    if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
       u16_t udpchksum;
 #if LWIP_CHECKSUM_ON_COPY
       if (have_chksum) {
         u32_t acc;
-        udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
-          q->tot_len, UDP_HLEN);
+        udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP,
+          q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
         acc = udpchksum + (u16_t)~(chksum);
         udpchksum = FOLD_U32T(acc);
       } else
 #endif /* LWIP_CHECKSUM_ON_COPY */
       {
-        udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
+        udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len,
+          ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
       }
 
       /* chksum zero must become 0xffff, as zero means 'no checksum' */
       if (udpchksum == 0x0000) {
         udpchksum = 0xffff;
-    }
+      }
       udphdr->chksum = udpchksum;
     }
 #endif /* CHECKSUM_GEN_UDP */
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
-    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
-    /* output to IP */
-#if LWIP_NETIF_HWADDRHINT
-    netif->addr_hint = &(pcb->addr_hint);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
-#if LWIP_NETIF_HWADDRHINT
-    netif->addr_hint = NULL;
-#endif /* LWIP_NETIF_HWADDRHINT*/
+    ip_proto = IP_PROTO_UDP;
   }
+
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto));
+  /* output to IP */
+  NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
+  err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif);
+  NETIF_SET_HWADDRHINT(netif, NULL);
+
   /* TODO: must this be increased even if error occured? */
   snmp_inc_udpoutdatagrams();
 
@@ -695,7 +809,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
   u8_t rebind;
 
   LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
-  ip_addr_debug_print(UDP_DEBUG, ipaddr);
+  ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr));
   LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
 
   rebind = 0;
@@ -719,11 +833,11 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
     /* port matches that of PCB in list and REUSEADDR not set -> reject */
     else {
 #endif /* SO_REUSE */
-      if ((ipcb->local_port == port) &&
+      if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) &&
           /* IP address matches, or one is IP_ADDR_ANY? */
-          (ip_addr_isany(&(ipcb->local_ip)) ||
-           ip_addr_isany(ipaddr) ||
-           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
+            (ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) ||
+             ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) ||
+             ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) {
         /* other PCB already binds to this local IP and port */
         LWIP_DEBUGF(UDP_DEBUG,
                     ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
@@ -732,13 +846,15 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
     }
   }
 
-  ip_addr_set(&pcb->local_ip, ipaddr);
+  ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
 
   /* no port specified? */
   if (port == 0) {
 #ifndef UDP_LOCAL_PORT_RANGE_START
-#define UDP_LOCAL_PORT_RANGE_START 4096
-#define UDP_LOCAL_PORT_RANGE_END   0x7fff
+/* From http://www.iana.org/assignments/port-numbers:
+   "The Dynamic and/or Private Ports are those from 49152 through 65535" */
+#define UDP_LOCAL_PORT_RANGE_START  0xc000
+#define UDP_LOCAL_PORT_RANGE_END    0xffff
 #endif
     port = UDP_LOCAL_PORT_RANGE_START;
     ipcb = udp_pcbs;
@@ -751,7 +867,7 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
       } else {
         /* go on with next udp pcb */
         ipcb = ipcb->next;
-    }
+      }
     }
     if (ipcb != NULL) {
       /* no more ports available in local range */
@@ -767,13 +883,12 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
     pcb->next = udp_pcbs;
     udp_pcbs = pcb;
   }
-  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
-              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
-               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
-               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
-               pcb->local_port));
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));
+  ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip);
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
   return ERR_OK;
 }
+
 /**
  * Connect an UDP PCB.
  *
@@ -797,39 +912,44 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
   struct udp_pcb *ipcb;
 
   if (pcb->local_port == 0) {
-    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
+    err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
     if (err != ERR_OK) {
       return err;
-  }
+    }
   }
 
-  ip_addr_set(&pcb->remote_ip, ipaddr);
+  ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
   pcb->remote_port = port;
   pcb->flags |= UDP_FLAGS_CONNECTED;
 /** TODO: this functionality belongs in upper layers */
 #ifdef LWIP_UDP_TODO
-  /* Nail down local IP for netconn_addr()/getsockname() */
-  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
-    struct netif *netif;
-
-    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
-      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
-      UDP_STATS_INC(udp.rterr);
-      return ERR_RTE;
+#if LWIP_IPV6
+  if (!PCB_ISIPV6(pcb))
+#endif /* LWIP_IPV6 */
+  {
+    /* Nail down local IP for netconn_addr()/getsockname() */
+    if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
+      struct netif *netif;
+
+      if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) {
+        LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n",
+                    ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip))));
+        UDP_STATS_INC(udp.rterr);
+        return ERR_RTE;
+      }
+      /** TODO: this will bind the udp pcb locally, to the interface which
+          is used to route output packets to the remote address. However, we
+          might want to accept incoming packets on any interface! */
+      ipX_addr_copy(0, pcb->local_ip, netif->ip_addr);
+    } else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
+      ipX_addr_set_any(0, &pcb->local_ip);
     }
-    /** TODO: this will bind the udp pcb locally, to the interface which
-        is used to route output packets to the remote address. However, we
-        might want to accept incoming packets on any interface! */
-    pcb->local_ip = netif->ip_addr;
-  } else if (ip_addr_isany(&pcb->remote_ip)) {
-    pcb->local_ip.addr = 0;
   }
 #endif
-  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
-              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
-               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
-               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
-               pcb->local_port));
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));
+  ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
+                       &pcb->remote_ip);
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));
 
   /* Insert UDP PCB into the list of active UDP PCBs. */
   for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
@@ -853,7 +973,7 @@ void
 udp_disconnect(struct udp_pcb *pcb)
 {
   /* reset remote address association */
-  ip_addr_set_any(&pcb->remote_ip);
+  ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip);
   pcb->remote_port = 0;
   /* mark PCB as unconnected */
   pcb->flags &= ~UDP_FLAGS_CONNECTED;
@@ -872,7 +992,7 @@ void
 udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
 {
   /* remember recv() callback and user data */
-  pcb->recv = recv;
+  pcb->recv.ip4 = recv;
   pcb->recv_arg = recv_arg;
 }
 
@@ -932,6 +1052,25 @@ udp_new(void)
   return pcb;
 }
 
+#if LWIP_IPV6
+/**
+ * Create a UDP PCB for IPv6.
+ *
+ * @return The UDP PCB which was created. NULL if the PCB data structure
+ * could not be allocated.
+ *
+ * @see udp_remove()
+ */
+struct udp_pcb *
+udp_new_ip6(void)
+{
+  struct udp_pcb *pcb;
+  pcb = udp_new();
+  ip_set_v6(pcb, 1);
+  return pcb;
+}
+#endif /* LWIP_IPV6 */
+
 #if UDP_DEBUG
 /**
  * Print UDP header information for debug purposes.
index 5b77c5e8aaa8eaa8d6ae9bd8ec6087e00e7fbb5b..e62b72e8cd8c2d9d1239fd8c918d59f33f7558a9 100644 (file)
@@ -80,7 +80,7 @@ extern "C" {
 
 struct autoip
 {
-  ip_addr_t llipaddr;  /* the currently selected, probed, announced or used LL IP-Address */
+  ip_addr_t llipaddr;       /* the currently selected, probed, announced or used LL IP-Address */
   u8_t state;               /* current AutoIP state machine state */
   u8_t sent_num;            /* sent number of probes or announces, dependent on state */
   u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
@@ -89,8 +89,7 @@ struct autoip
 };
 
 
-/** Init srand, has to be called before entering mainloop */
-void autoip_init(void);
+#define autoip_init() /* Compatibility define, no init needed. */
 
 /** Set a struct autoip allocated by the application to work with */
 void autoip_set_struct(struct netif *netif, struct autoip *autoip);
index c73961c917dd5e0ab73bab2d57e7f7677bf8270c..fa893b6b4453883c4b48ee481e816f3fb46299ec 100644 (file)
 #include "lwip/ip_addr.h"
 #include "lwip/netif.h"
 
+#if LWIP_IPV6 && LWIP_ICMP6
+#include "lwip/icmp6.h"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define ICMP_ER 0      /* echo reply */
-#define ICMP_DUR     /* destination unreachable */
-#define ICMP_SQ 4      /* source quench */
-#define ICMP_RD 5      /* redirect */
+#define ICMP_ER   0    /* echo reply */
+#define ICMP_DUR  3    /* destination unreachable */
+#define ICMP_SQ   4    /* source quench */
+#define ICMP_RD   5    /* redirect */
 #define ICMP_ECHO 8    /* echo */
-#define ICMP_TE 11     /* time exceeded */
-#define ICMP_PP 12     /* parameter problem */
-#define ICMP_TS 13     /* timestamp */
+#define ICMP_TE  11    /* time exceeded */
+#define ICMP_PP  12    /* parameter problem */
+#define ICMP_TS  13    /* timestamp */
 #define ICMP_TSR 14    /* timestamp reply */
 #define ICMP_IRQ 15    /* information request */
-#define ICMP_IR 16     /* information reply */
+#define ICMP_IR  16    /* information reply */
 
 enum icmp_dur_type {
-  ICMP_DUR_NET = 0,    /* net unreachable */
-  ICMP_DUR_HOST = 1,   /* host unreachable */
+  ICMP_DUR_NET   = 0,  /* net unreachable */
+  ICMP_DUR_HOST  = 1,  /* host unreachable */
   ICMP_DUR_PROTO = 2,  /* protocol unreachable */
-  ICMP_DUR_PORT = 3,   /* port unreachable */
-  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */
-  ICMP_DUR_SR = 5      /* source route failed */
+  ICMP_DUR_PORT  = 3,  /* port unreachable */
+  ICMP_DUR_FRAG  = 4,  /* fragmentation needed and DF set */
+  ICMP_DUR_SR    = 5   /* source route failed */
 };
 
 enum icmp_te_type {
-  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */
+  ICMP_TE_TTL  = 0,    /* time to live exceeded in transit */
   ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */
 };
 
@@ -104,6 +108,16 @@ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
 
 #endif /* LWIP_ICMP */
 
+#if (LWIP_IPV6 && LWIP_ICMP6)
+#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \
+                                         icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \
+                                         icmp_dest_unreach(pbuf, ICMP_DUR_PORT))
+#elif LWIP_ICMP
+#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT)
+#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
+#define icmp_port_unreach(isipv6, pbuf)
+#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
+
 #ifdef __cplusplus
 }
 #endif
index cb33486bf82211e5bd26bae15a1d68894ee69256..7bff49b59e61fc6ae8f5ef25f0514c43e1e4f11b 100644 (file)
@@ -91,6 +91,8 @@ struct in_addr {
 
 #define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
 #define inet_addr_to_ipaddr(target_ipaddr, source_inaddr)   (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
+/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
+#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr)   ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
 
 /* directly map this to the lwip internal functions */
 #define inet_addr(cp)         ipaddr_addr(cp)
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4.h
new file mode 100644 (file)
index 0000000..64c9b4d
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP4_H__
+#define __LWIP_IP4_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/err.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Currently, the function ip_output_if_opt() is only used with IGMP */
+#define IP_OPTIONS_SEND   LWIP_IGMP
+
+#define IP_HLEN 20
+
+#define IP_PROTO_ICMP    1
+#define IP_PROTO_IGMP    2
+#define IP_PROTO_UDP     17
+#define IP_PROTO_UDPLITE 136
+#define IP_PROTO_TCP     6
+
+
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_hdr {
+  /* version / header length */
+  PACK_STRUCT_FIELD(u8_t _v_hl);
+  /* type of service */
+  PACK_STRUCT_FIELD(u8_t _tos);
+  /* total length */
+  PACK_STRUCT_FIELD(u16_t _len);
+  /* identification */
+  PACK_STRUCT_FIELD(u16_t _id);
+  /* fragment offset field */
+  PACK_STRUCT_FIELD(u16_t _offset);
+#define IP_RF 0x8000U        /* reserved fragment flag */
+#define IP_DF 0x4000U        /* dont fragment flag */
+#define IP_MF 0x2000U        /* more fragments flag */
+#define IP_OFFMASK 0x1fffU   /* mask for fragmenting bits */
+  /* time to live */
+  PACK_STRUCT_FIELD(u8_t _ttl);
+  /* protocol*/
+  PACK_STRUCT_FIELD(u8_t _proto);
+  /* checksum */
+  PACK_STRUCT_FIELD(u16_t _chksum);
+  /* source and destination IP addresses */
+  PACK_STRUCT_FIELD(ip_addr_p_t src);
+  PACK_STRUCT_FIELD(ip_addr_p_t dest); 
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPH_V(hdr)  ((hdr)->_v_hl >> 4)
+#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f)
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IPH_V(hdr)  ((hdr)->_v_hl & 0x0f)
+#define IPH_HL(hdr) ((hdr)->_v_hl >> 4)
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IPH_TOS(hdr) ((hdr)->_tos)
+#define IPH_LEN(hdr) ((hdr)->_len)
+#define IPH_ID(hdr) ((hdr)->_id)
+#define IPH_OFFSET(hdr) ((hdr)->_offset)
+#define IPH_TTL(hdr) ((hdr)->_ttl)
+#define IPH_PROTO(hdr) ((hdr)->_proto)
+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl))
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = ((v) | ((hl) << 4))
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos)
+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
+#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
+
+
+#define ip_init() /* Compatibility define, no init needed. */
+struct netif *ip_route(ip_addr_t *dest);
+err_t ip_input(struct pbuf *p, struct netif *inp);
+err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto);
+err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto,
+       struct netif *netif);
+#if LWIP_NETIF_HWADDRHINT
+err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT */
+#if IP_OPTIONS_SEND
+err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
+       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
+       u16_t optlen);
+#endif /* IP_OPTIONS_SEND */
+
+#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL)
+
+#if IP_DEBUG
+void ip_debug_print(struct pbuf *p);
+#else
+#define ip_debug_print(p)
+#endif /* IP_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_H__ */
+
+
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4_addr.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv4/lwip/ip4_addr.h
new file mode 100644 (file)
index 0000000..b05ae53
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP4_ADDR_H__
+#define __LWIP_IP4_ADDR_H__
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is the aligned version of ip_addr_t,
+   used as local variable, on the stack, etc. */
+struct ip_addr {
+  u32_t addr;
+};
+
+/* This is the packed version of ip_addr_t,
+   used in network headers that are itself packed */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr_packed {
+  PACK_STRUCT_FIELD(u32_t addr);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** ip_addr_t uses a struct for convenience only, so that the same defines can
+ * operate both on ip_addr_t as well as on ip_addr_p_t. */
+typedef struct ip_addr ip_addr_t;
+typedef struct ip_addr_packed ip_addr_p_t;
+
+/*
+ * struct ipaddr2 is used in the definition of the ARP packet format in
+ * order to support compilers that don't have structure packing.
+ */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip_addr2 {
+  PACK_STRUCT_FIELD(u16_t addrw[2]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* Forward declaration to not include netif.h */
+struct netif;
+
+extern const ip_addr_t ip_addr_any;
+extern const ip_addr_t ip_addr_broadcast;
+
+/** IP_ADDR_ can be used as a fixed IP address
+ *  for the wildcard and the broadcast address
+ */
+#define IP_ADDR_ANY         ((ip_addr_t *)&ip_addr_any)
+#define IP_ADDR_BROADCAST   ((ip_addr_t *)&ip_addr_broadcast)
+
+/** 255.255.255.255 */
+#define IPADDR_NONE         ((u32_t)0xffffffffUL)
+/** 127.0.0.1 */
+#define IPADDR_LOOPBACK     ((u32_t)0x7f000001UL)
+/** 0.0.0.0 */
+#define IPADDR_ANY          ((u32_t)0x00000000UL)
+/** 255.255.255.255 */
+#define IPADDR_BROADCAST    ((u32_t)0xffffffffUL)
+
+/* Definitions of the bits in an Internet address integer.
+
+   On subnets, host and network parts are found according to
+   the subnet mask, not these masks.  */
+#define IP_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0)
+#define IP_CLASSA_NET       0xff000000
+#define IP_CLASSA_NSHIFT    24
+#define IP_CLASSA_HOST      (0xffffffff & ~IP_CLASSA_NET)
+#define IP_CLASSA_MAX       128
+
+#define IP_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
+#define IP_CLASSB_NET       0xffff0000
+#define IP_CLASSB_NSHIFT    16
+#define IP_CLASSB_HOST      (0xffffffff & ~IP_CLASSB_NET)
+#define IP_CLASSB_MAX       65536
+
+#define IP_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
+#define IP_CLASSC_NET       0xffffff00
+#define IP_CLASSC_NSHIFT    8
+#define IP_CLASSC_HOST      (0xffffffff & ~IP_CLASSC_NET)
+
+#define IP_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
+#define IP_CLASSD_NET       0xf0000000          /* These ones aren't really */
+#define IP_CLASSD_NSHIFT    28                  /*   net and host fields, but */
+#define IP_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */
+#define IP_MULTICAST(a)     IP_CLASSD(a)
+
+#define IP_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
+#define IP_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
+
+#define IP_LOOPBACKNET      127                 /* official! */
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+/** Set an IP address given by the four byte-parts */
+#define IP4_ADDR(ipaddr, a,b,c,d) \
+        (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
+                         ((u32_t)((b) & 0xff) << 16) | \
+                         ((u32_t)((c) & 0xff) << 8)  | \
+                          (u32_t)((d) & 0xff)
+#else
+/** Set an IP address given by the four byte-parts.
+    Little-endian version that prevents the use of htonl. */
+#define IP4_ADDR(ipaddr, a,b,c,d) \
+        (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
+                         ((u32_t)((c) & 0xff) << 16) | \
+                         ((u32_t)((b) & 0xff) << 8)  | \
+                          (u32_t)((a) & 0xff)
+#endif
+
+/** MEMCPY-like copying of IP addresses where addresses are known to be
+ * 16-bit-aligned if the port is correctly configured (so a port could define
+ * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
+#ifndef IPADDR2_COPY
+#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
+#endif
+
+/** Copy IP address - faster than ip_addr_set: no NULL check */
+#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
+/** Safely copy one IP address to another (src may be NULL) */
+#define ip_addr_set(dest, src) ((dest)->addr = \
+                                    ((src) == NULL ? 0 : \
+                                    (src)->addr))
+/** Set complete address to zero */
+#define ip_addr_set_zero(ipaddr)      ((ipaddr)->addr = 0)
+/** Set address to IPADDR_ANY (no need for htonl()) */
+#define ip_addr_set_any(ipaddr)       ((ipaddr)->addr = IPADDR_ANY)
+/** Set address to loopback address */
+#define ip_addr_set_loopback(ipaddr)  ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
+/** Safely copy one IP address to another and change byte order
+ * from host- to network-order. */
+#define ip_addr_set_hton(dest, src) ((dest)->addr = \
+                               ((src) == NULL ? 0:\
+                               htonl((src)->addr)))
+/** IPv4 only: set the IP address given as an u32_t */
+#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
+/** IPv4 only: get the IP address as an u32_t */
+#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
+
+/** Get the network address by combining host address with netmask */
+#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
+
+/**
+ * Determine if two address are on the same network.
+ *
+ * @arg addr1 IP address 1
+ * @arg addr2 IP address 2
+ * @arg mask network identifier mask
+ * @return !0 if the network identifiers of both address match
+ */
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
+                                              (mask)->addr) == \
+                                             ((addr2)->addr & \
+                                              (mask)->addr))
+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
+
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
+
+#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
+u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
+
+#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
+u8_t ip4_addr_netmask_valid(u32_t netmask);
+
+#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
+
+#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
+
+#define ip_addr_debug_print(debug, ipaddr) \
+  LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F,             \
+                      ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0,       \
+                      ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0,       \
+                      ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0,       \
+                      ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
+
+/* Get one byte from the 4-byte address */
+#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
+#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
+#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
+#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
+/* These are cast to u16_t, with the intent that they are often arguments
+ * to printf using the U16_F format from cc.h. */
+#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
+#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
+#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
+#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
+
+/** For backwards compatibility */
+#define ip_ntoa(ipaddr)  ipaddr_ntoa(ipaddr)
+
+u32_t ipaddr_addr(const char *cp);
+int ipaddr_aton(const char *cp, ip_addr_t *addr);
+/** returns ptr to static buffer; not reentrant! */
+char *ipaddr_ntoa(const ip_addr_t *addr);
+char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_ADDR_H__ */
index 97ab7416d69c1b16f49c9e549ba3cbfb09741ee4..47eca9f42ca3ce31b56aeb199df90ecd1b531954 100644 (file)
@@ -66,6 +66,21 @@ struct pbuf * ip_reass(struct pbuf *p);
 #endif /* IP_REASSEMBLY */
 
 #if IP_FRAG
+#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
+/** A custom pbuf that holds a reference to another pbuf, which is freed
+ * when this custom pbuf is freed. This is used to create a custom PBUF_REF
+ * that points into the original pbuf. */
+#ifndef __LWIP_PBUF_CUSTOM_REF__
+#define __LWIP_PBUF_CUSTOM_REF__
+struct pbuf_custom_ref {
+  /** 'base class' */
+  struct pbuf_custom pc;
+  /** pointer to the original pbuf that is referenced */
+  struct pbuf *original;
+};
+#endif /* __LWIP_PBUF_CUSTOM_REF__ */
+#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
+
 err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
 #endif /* IP_FRAG */
 
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/dhcp6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/dhcp6.h
new file mode 100644 (file)
index 0000000..83ce306
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @file
+ *
+ * IPv6 address autoconfiguration as per RFC 4862.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ * IPv6 address autoconfiguration as per RFC 4862.
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#ifndef __LWIP_IP6_DHCP6_H__
+#define __LWIP_IP6_DHCP6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6_DHCP6  /* don't build if not configured for use in lwipopts.h */
+
+
+struct dhcp6
+{
+  //TODO: implement DHCP6
+};
+
+#endif /* LWIP_IPV6_DHCP6 */
+
+#endif /* __LWIP_IP6_DHCP6_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ethip6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ethip6.h
new file mode 100644 (file)
index 0000000..e7f412b
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * @file
+ *
+ * Ethernet output for IPv6. Uses ND tables for link-layer addressing.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#ifndef __LWIP_ETHIP6_H__
+#define __LWIP_ETHIP6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/netif.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6 && LWIP_ETHERNET */
+
+#endif /* __LWIP_ETHIP6_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/icmp6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/icmp6.h
new file mode 100644 (file)
index 0000000..74bfdbe
--- /dev/null
@@ -0,0 +1,152 @@
+/**
+ * @file
+ *
+ * IPv6 version of ICMP, as per RFC 4443.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+#ifndef __LWIP_ICMP6_H__
+#define __LWIP_ICMP6_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/netif.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum icmp6_type {
+  ICMP6_TYPE_DUR = 1,  /* Destination unreachable */
+  ICMP6_TYPE_PTB = 2,  /* Packet too big */
+  ICMP6_TYPE_TE = 3,   /* Time exceeded */
+  ICMP6_TYPE_PP = 4,   /* Parameter problem */
+  ICMP6_TYPE_PE1 = 100,  /* Private experimentation */
+  ICMP6_TYPE_PE2 = 101,  /* Private experimentation */
+  ICMP6_TYPE_RSV_ERR = 127,  /* Reserved for expansion of error messages */
+
+  ICMP6_TYPE_EREQ = 128,  /* Echo request */
+  ICMP6_TYPE_EREP = 129,  /* Echo reply */
+  ICMP6_TYPE_MLQ = 130,  /* Multicast listener query */
+  ICMP6_TYPE_MLR = 131,  /* Multicast listener report */
+  ICMP6_TYPE_MLD = 132,  /* Multicast listener done */
+  ICMP6_TYPE_RS = 133,  /* Router solicitation */
+  ICMP6_TYPE_RA = 134,  /* Router advertisement */
+  ICMP6_TYPE_NS = 135,  /* Neighbor solicitation */
+  ICMP6_TYPE_NA = 136,  /* Neighbor advertisement */
+  ICMP6_TYPE_RD = 137,  /* Redirect */
+  ICMP6_TYPE_MRA = 151,  /* Multicast router advertisement */
+  ICMP6_TYPE_MRS = 152,  /* Multicast router solicitation */
+  ICMP6_TYPE_MRT = 153,  /* Multicast router termination */
+  ICMP6_TYPE_PE3 = 200,  /* Private experimentation */
+  ICMP6_TYPE_PE4 = 201,  /* Private experimentation */
+  ICMP6_TYPE_RSV_INF = 255  /* Reserved for expansion of informational messages */
+};
+
+enum icmp6_dur_code {
+  ICMP6_DUR_NO_ROUTE = 0,     /* No route to destination */
+  ICMP6_DUR_PROHIBITED = 1,   /* Communication with destination administratively prohibited */
+  ICMP6_DUR_SCOPE = 2,        /* Beyond scope of source address */
+  ICMP6_DUR_ADDRESS = 3,      /* Address unreachable */
+  ICMP6_DUR_PORT = 4,         /* Port unreachable */
+  ICMP6_DUR_POLICY = 5,       /* Source address failed ingress/egress policy */
+  ICMP6_DUR_REJECT_ROUTE = 6  /* Reject route to destination */
+};
+
+enum icmp6_te_code {
+  ICMP6_TE_HL = 0,   /* Hop limit exceeded in transit */
+  ICMP6_TE_FRAG = 1  /* Fragment reassembly time exceeded */
+};
+
+enum icmp6_pp_code {
+  ICMP6_PP_FIELD = 0,   /* Erroneous header field encountered */
+  ICMP6_PP_HEADER = 1,  /* Unrecognized next header type encountered */
+  ICMP6_PP_OPTION = 2   /* Unrecognized IPv6 option encountered */
+};
+
+/** This is the standard ICMP6 header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct icmp6_hdr {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t data);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** This is the ICMP6 header adapted for echo req/resp. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct icmp6_echo_hdr {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u16_t id);
+  PACK_STRUCT_FIELD(u16_t seqno);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+
+#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
+
+void icmp6_input(struct pbuf *p, struct netif *inp);
+void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c);
+void icmp6_packet_too_big(struct pbuf *p, u32_t mtu);
+void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c);
+void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer);
+
+#endif /* LWIP_ICMP6 && LWIP_IPV6 */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __LWIP_ICMP6_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/inet6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/inet6.h
new file mode 100644 (file)
index 0000000..fbbdcf1
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * @file
+ *
+ * INET v6 addresses.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+#ifndef __LWIP_INET6_H__
+#define __LWIP_INET6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/ip6_addr.h"
+#include "lwip/def.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** For compatibility with BSD code */
+struct in6_addr {
+  u32_t s_addr[4];
+};
+
+#define IN6ADDR_ANY_INIT {0,0,0,0}
+#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)}
+
+
+
+#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s_addr[0] = (source_ip6addr)->addr[0]; \
+                                                                 (target_in6addr)->s_addr[1] = (source_ip6addr)->addr[1]; \
+                                                                 (target_in6addr)->s_addr[2] = (source_ip6addr)->addr[2]; \
+                                                                 (target_in6addr)->s_addr[3] = (source_ip6addr)->addr[3];}
+#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr)   {(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
+                                                                 (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
+                                                                 (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
+                                                                 (target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0];}
+/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */
+#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr)   ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr))
+
+/* directly map this to the lwip internal functions */
+#define inet6_aton(cp, addr)   ip6addr_aton(cp, (ip6_addr_t*)addr)
+#define inet6_ntoa(addr)       ip6addr_ntoa((ip6_addr_t*)&(addr))
+#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6 */
+
+#endif /* __LWIP_INET6_H__ */
+
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6.h
new file mode 100644 (file)
index 0000000..b199c95
--- /dev/null
@@ -0,0 +1,197 @@
+/**
+ * @file
+ *
+ * IPv6 layer.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+#ifndef __LWIP_IP6_H__
+#define __LWIP_IP6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/ip.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+
+#include "lwip/err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IP6_HLEN 40
+
+#define IP6_NEXTH_HOPBYHOP  0
+#define IP6_NEXTH_TCP       6
+#define IP6_NEXTH_UDP       17
+#define IP6_NEXTH_ENCAPS    41
+#define IP6_NEXTH_ROUTING   43
+#define IP6_NEXTH_FRAGMENT  44
+#define IP6_NEXTH_ICMP6     58
+#define IP6_NEXTH_NONE      59
+#define IP6_NEXTH_DESTOPTS  60
+#define IP6_NEXTH_UDPLITE   136
+
+
+/* The IPv6 header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip6_hdr {
+  /* version / traffic class / flow label */
+  PACK_STRUCT_FIELD(u32_t _v_tc_fl);
+  /* payload length */
+  PACK_STRUCT_FIELD(u16_t _plen);
+  /* next header */
+  PACK_STRUCT_FIELD(u8_t _nexth);
+  /* hop limit */
+  PACK_STRUCT_FIELD(u8_t _hoplim);
+  /* source and destination IP addresses */
+  PACK_STRUCT_FIELD(ip6_addr_p_t src);
+  PACK_STRUCT_FIELD(ip6_addr_p_t dest);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* Hop-by-hop router alert option. */
+#define IP6_HBH_HLEN    8
+#define IP6_PAD1_OPTION         0
+#define IP6_PADN_ALERT_OPTION   1
+#define IP6_ROUTER_ALERT_OPTION 5
+#define IP6_ROUTER_ALERT_VALUE_MLD 0
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip6_hbh_hdr {
+  /* next header */
+  PACK_STRUCT_FIELD(u8_t _nexth);
+  /* header length */
+  PACK_STRUCT_FIELD(u8_t _hlen);
+  /* router alert option type */
+  PACK_STRUCT_FIELD(u8_t _ra_opt_type);
+  /* router alert option data len */
+  PACK_STRUCT_FIELD(u8_t _ra_opt_dlen);
+  /* router alert option data */
+  PACK_STRUCT_FIELD(u16_t _ra_opt_data);
+  /* PadN option type */
+  PACK_STRUCT_FIELD(u8_t _padn_opt_type);
+  /* PadN option data len */
+  PACK_STRUCT_FIELD(u8_t _padn_opt_dlen);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* Fragment header. */
+#define IP6_FRAG_HLEN    8
+#define IP6_FRAG_OFFSET_MASK    0xfff8
+#define IP6_FRAG_MORE_FLAG      0x0001
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip6_frag_hdr {
+  /* next header */
+  PACK_STRUCT_FIELD(u8_t _nexth);
+  /* reserved */
+  PACK_STRUCT_FIELD(u8_t reserved);
+  /* fragment offset */
+  PACK_STRUCT_FIELD(u16_t _fragment_offset);
+  /* fragmented packet identification */
+  PACK_STRUCT_FIELD(u32_t _identification);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define IP6H_V(hdr)  ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f)
+#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff)
+#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff)
+#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen))
+#define IP6H_NEXTH(hdr) ((hdr)->_nexth)
+#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6)
+#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim)
+
+#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl)))
+#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen)
+#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth)
+#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl)
+
+
+#define ip6_init() /* TODO should we init current addresses and header pointer? */
+struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest);
+ip6_addr_t   *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest);
+err_t         ip6_input(struct pbuf *p, struct netif *inp);
+err_t         ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
+                         u8_t hl, u8_t tc, u8_t nexth);
+err_t         ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
+                            u8_t hl, u8_t tc, u8_t nexth, struct netif *netif);
+#if LWIP_NETIF_HWADDRHINT
+err_t         ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
+                                u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint);
+#endif /* LWIP_NETIF_HWADDRHINT */
+#if LWIP_IPV6_MLD
+err_t         ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value);
+#endif /* LWIP_IPV6_MLD */
+
+#define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \
+  ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL)
+
+#if IP6_DEBUG
+void ip6_debug_print(struct pbuf *p);
+#else
+#define ip6_debug_print(p)
+#endif /* IP6_DEBUG */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6 */
+
+#endif /* __LWIP_IP6_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_addr.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_addr.h
new file mode 100644 (file)
index 0000000..68e93e0
--- /dev/null
@@ -0,0 +1,282 @@
+/**
+ * @file
+ *
+ * IPv6 addresses.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ * Structs and macros for handling IPv6 addresses.
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+#ifndef __LWIP_IP6_ADDR_H__
+#define __LWIP_IP6_ADDR_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This is the aligned version of ip6_addr_t,
+   used as local variable, on the stack, etc. */
+struct ip6_addr {
+  u32_t addr[4];
+};
+
+/* This is the packed version of ip6_addr_t,
+   used in network headers that are itself packed */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ip6_addr_packed {
+  PACK_STRUCT_FIELD(u32_t addr[4]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** ip6_addr_t uses a struct for convenience only, so that the same defines can
+ * operate both on ip6_addr_t as well as on ip6_addr_p_t. */
+typedef struct ip6_addr ip6_addr_t;
+typedef struct ip6_addr_packed ip6_addr_p_t;
+
+
+/** IP6_ADDR_ANY can be used as a fixed IPv6 address
+ *  for the wildcard
+ */
+extern const ip6_addr_t ip6_addr_any;
+#define IP6_ADDR_ANY         ((ip6_addr_t *)&ip6_addr_any)
+
+
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+/** Set an IPv6 partial address given by byte-parts. */
+#define IP6_ADDR(ip6addr, index, a,b,c,d) \
+  (ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \
+                           ((u32_t)((b) & 0xff) << 16) | \
+                           ((u32_t)((c) & 0xff) << 8)  | \
+                            (u32_t)((d) & 0xff)
+#else
+/** Set an IPv6 partial address given by byte-parts.
+Little-endian version, stored in network order (no htonl). */
+#define IP6_ADDR(ip6addr, index, a,b,c,d) \
+  (ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \
+                           ((u32_t)((c) & 0xff) << 16) | \
+                           ((u32_t)((b) & 0xff) << 8)  | \
+                            (u32_t)((a) & 0xff)
+#endif
+
+/** Access address in 16-bit block */
+#define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0]) >> 16) & 0xffff)
+#define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0])) & 0xffff)
+#define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1]) >> 16) & 0xffff)
+#define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1])) & 0xffff)
+#define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2]) >> 16) & 0xffff)
+#define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2])) & 0xffff)
+#define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3]) >> 16) & 0xffff)
+#define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3])) & 0xffff)
+
+/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */
+#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \
+                                    (dest).addr[1] = (src).addr[1]; \
+                                    (dest).addr[2] = (src).addr[2]; \
+                                    (dest).addr[3] = (src).addr[3];}while(0)
+/** Safely copy one IPv6 address to another (src may be NULL) */
+#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \
+                                   (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \
+                                   (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \
+                                   (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0)
+
+/** Set complete address to zero */
+#define ip6_addr_set_zero(ip6addr)    do{(ip6addr)->addr[0] = 0; \
+                                         (ip6addr)->addr[1] = 0; \
+                                         (ip6addr)->addr[2] = 0; \
+                                         (ip6addr)->addr[3] = 0;}while(0)
+
+/** Set address to ipv6 'any' (no need for htonl()) */
+#define ip6_addr_set_any(ip6addr)       ip6_addr_set_zero(ip6addr)
+/** Set address to ipv6 loopback address */
+#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \
+                                          (ip6addr)->addr[1] = 0; \
+                                          (ip6addr)->addr[2] = 0; \
+                                          (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
+/** Safely copy one IPv6 address to another and change byte order
+ * from host- to network-order. */
+#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \
+                                        (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \
+                                        (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \
+                                        (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0)
+
+
+
+/**
+ * Determine if two IPv6 address are on the same network.
+ *
+ * @arg addr1 IPv6 address 1
+ * @arg addr2 IPv6 address 2
+ * @return !0 if the network identifiers of both address match
+ */
+#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
+                                       ((addr1)->addr[1] == (addr2)->addr[1]))
+
+#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
+                                    ((addr1)->addr[1] == (addr2)->addr[1]) && \
+                                    ((addr1)->addr[2] == (addr2)->addr[2]) && \
+                                    ((addr1)->addr[3] == (addr2)->addr[3]))
+
+#define ip6_get_subnet_id(ip6addr)   (htonl((ip6addr)->addr[2]) & 0x0000ffffUL)
+
+#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \
+                             (((ip6addr)->addr[0] == 0) && \
+                             ((ip6addr)->addr[1] == 0) && \
+                             ((ip6addr)->addr[2] == 0) && \
+                             ((ip6addr)->addr[3] == 0)))
+
+
+#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL))
+
+#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL))
+
+#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL))
+
+#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL))
+
+#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL))
+#define ip6_addr_multicast_transient_flag(ip6addr)  ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL))
+#define ip6_addr_multicast_prefix_flag(ip6addr)     ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL))
+#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL))
+#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf)
+#define IP6_MULTICAST_SCOPE_RESERVED            0x0
+#define IP6_MULTICAST_SCOPE_RESERVED0           0x0
+#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL     0x1
+#define IP6_MULTICAST_SCOPE_LINK_LOCAL          0x2
+#define IP6_MULTICAST_SCOPE_RESERVED3           0x3
+#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL         0x4
+#define IP6_MULTICAST_SCOPE_SITE_LOCAL          0x5
+#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL  0x8
+#define IP6_MULTICAST_SCOPE_GLOBAL              0xe
+#define IP6_MULTICAST_SCOPE_RESERVEDF           0xf
+#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL))
+#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL))
+#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL))
+#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL))
+#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL))
+#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL))
+
+/* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */
+#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \
+    ((ip6addr)->addr[1] == 0UL) && \
+    ((ip6addr)->addr[2] == 0UL) && \
+    ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
+
+#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
+    ((ip6addr)->addr[1] == 0UL) && \
+    ((ip6addr)->addr[2] == 0UL) && \
+    ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
+#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
+                (ip6addr)->addr[1] = 0; \
+                (ip6addr)->addr[2] = 0; \
+                (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
+
+#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
+    ((ip6addr)->addr[1] == 0UL) && \
+    ((ip6addr)->addr[2] == 0UL) && \
+    ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL)))
+#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
+                (ip6addr)->addr[1] = 0; \
+                (ip6addr)->addr[2] = 0; \
+                (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0)
+
+#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
+        ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \
+        (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) )
+
+#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
+                (ip6addr)->addr[1] = 0; \
+                (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \
+                (ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}while(0)
+
+
+/* IPv6 address states. */
+#define IP6_ADDR_INVALID      0x00
+#define IP6_ADDR_TENTATIVE    0x08
+#define IP6_ADDR_TENTATIVE_1  0x09 /* 1 probe sent */
+#define IP6_ADDR_TENTATIVE_2  0x0a /* 2 probes sent */
+#define IP6_ADDR_TENTATIVE_3  0x0b /* 3 probes sent */
+#define IP6_ADDR_TENTATIVE_4  0x0c /* 4 probes sent */
+#define IP6_ADDR_TENTATIVE_5  0x0d /* 5 probes sent */
+#define IP6_ADDR_TENTATIVE_6  0x0e /* 6 probes sent */
+#define IP6_ADDR_TENTATIVE_7  0x0f /* 7 probes sent */
+#define IP6_ADDR_VALID        0x10
+#define IP6_ADDR_PREFERRED    0x30
+#define IP6_ADDR_DEPRECATED   0x50
+
+#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID)
+#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE)
+#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
+#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
+#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
+
+#define ip6_addr_debug_print(debug, ipaddr) \
+  LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0,    \
+                      ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0))
+
+int ip6addr_aton(const char *cp, ip6_addr_t *addr);
+/** returns ptr to static buffer; not reentrant! */
+char *ip6addr_ntoa(const ip6_addr_t *addr);
+char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6 */
+
+#endif /* __LWIP_IP6_ADDR_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_frag.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/ip6_frag.h
new file mode 100644 (file)
index 0000000..75898b8
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * @file
+ *
+ * IPv6 fragmentation and reassembly.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+#ifndef __LWIP_IP6_FRAG_H__
+#define __LWIP_IP6_FRAG_H__
+
+#include "lwip/opt.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/netif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if LWIP_IPV6 && LWIP_IPV6_REASS  /* don't build if not configured for use in lwipopts.h */
+
+/* The IPv6 reassembly timer interval in milliseconds. */
+#define IP6_REASS_TMR_INTERVAL 1000
+
+/* IPv6 reassembly helper struct.
+ * This is exported because memp needs to know the size.
+ */
+struct ip6_reassdata {
+  struct ip6_reassdata *next;
+  struct pbuf *p;
+  struct ip6_hdr * iphdr;
+  u32_t identification;
+  u16_t datagram_len;
+  u8_t nexth;
+  u8_t timer;
+};
+
+#define ip6_reass_init() /* Compatibility define */
+void ip6_reass_tmr(void);
+struct pbuf * ip6_reass(struct pbuf *p);
+
+#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
+
+#if LWIP_IPV6 && LWIP_IPV6_FRAG  /* don't build if not configured for use in lwipopts.h */
+
+/** A custom pbuf that holds a reference to another pbuf, which is freed
+ * when this custom pbuf is freed. This is used to create a custom PBUF_REF
+ * that points into the original pbuf. */
+#ifndef __LWIP_PBUF_CUSTOM_REF__
+#define __LWIP_PBUF_CUSTOM_REF__
+struct pbuf_custom_ref {
+  /** 'base class' */
+  struct pbuf_custom pc;
+  /** pointer to the original pbuf that is referenced */
+  struct pbuf *original;
+};
+#endif /* __LWIP_PBUF_CUSTOM_REF__ */
+
+err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest);
+
+#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP6_FRAG_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/mld6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/mld6.h
new file mode 100644 (file)
index 0000000..abd86e5
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * @file
+ *
+ * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
+ * No support for MLDv2.
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#ifndef __LWIP_MLD6_H__
+#define __LWIP_MLD6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6_MLD && LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/netif.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mld_group {
+  /** next link */
+  struct mld_group *next;
+  /** interface on which the group is active */
+  struct netif      *netif;
+  /** multicast address */
+  ip6_addr_t         group_address;
+  /** signifies we were the last person to report */
+  u8_t               last_reporter_flag;
+  /** current state of the group */
+  u8_t               group_state;
+  /** timer for reporting */
+  u16_t              timer;
+  /** counter of simultaneous uses */
+  u8_t               use;
+};
+
+/** Multicast listener report/query/done message header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct mld_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u16_t max_resp_delay);
+  PACK_STRUCT_FIELD(u16_t reserved);
+  PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+#define MLD6_TMR_INTERVAL              100 /* Milliseconds */
+
+/* MAC Filter Actions, these are passed to a netif's
+ * mld_mac_filter callback function. */
+#define MLD6_DEL_MAC_FILTER            0
+#define MLD6_ADD_MAC_FILTER            1
+
+
+#define mld6_init() /* TODO should we init tables? */
+err_t  mld6_stop(struct netif *netif);
+void   mld6_report_groups(struct netif *netif);
+void   mld6_tmr(void);
+struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr);
+void   mld6_input(struct pbuf *p, struct netif *inp);
+err_t  mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
+err_t  mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */
+
+#endif /* __LWIP_MLD6_H__ */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/nd6.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/ipv6/lwip/nd6.h
new file mode 100644 (file)
index 0000000..3009f76
--- /dev/null
@@ -0,0 +1,368 @@
+/**
+ * @file
+ *
+ * Neighbor discovery and stateless address autoconfiguration for IPv6.
+ * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
+ * (Address autoconfiguration).
+ */
+
+/*
+ * Copyright (c) 2010 Inico Technologies Ltd.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Ivan Delamer <delamer@inicotech.com>
+ *
+ *
+ * Please coordinate changes and requests with Ivan Delamer
+ * <delamer@inicotech.com>
+ */
+
+#ifndef __LWIP_ND6_H__
+#define __LWIP_ND6_H__
+
+#include "lwip/opt.h"
+
+#if LWIP_IPV6  /* don't build if not configured for use in lwipopts.h */
+
+#include "lwip/pbuf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
+#include "lwip/netif.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct for tables. */
+struct nd6_neighbor_cache_entry {
+  ip6_addr_t next_hop_address;
+  struct netif * netif;
+  u8_t lladdr[NETIF_MAX_HWADDR_LEN];
+  /*u32_t pmtu;*/
+#if LWIP_ND6_QUEUEING
+  /** Pointer to queue of pending outgoing packets on this entry. */
+  struct nd6_q_entry *q;
+#endif /* LWIP_ND6_QUEUEING */
+  u8_t state;
+  u8_t isrouter;
+  union {
+    u32_t reachable_time;
+    u32_t delay_time;
+    u32_t probes_sent;
+    u32_t stale_time;
+  } counter;
+};
+
+struct nd6_destination_cache_entry {
+  ip6_addr_t destination_addr;
+  ip6_addr_t next_hop_addr;
+  u32_t pmtu;
+  u32_t age;
+};
+
+struct nd6_prefix_list_entry {
+  ip6_addr_t prefix;
+  struct netif * netif;
+  u32_t invalidation_timer;
+#if LWIP_IPV6_AUTOCONFIG
+  u8_t flags;
+#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
+#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
+#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
+#endif /* LWIP_IPV6_AUTOCONFIG */
+};
+
+struct nd6_router_list_entry {
+  struct nd6_neighbor_cache_entry * neighbor_entry;
+  u32_t invalidation_timer;
+  u8_t flags;
+};
+
+
+enum nd6_neighbor_cache_entry_state {
+  ND6_NO_ENTRY = 0,
+  ND6_INCOMPLETE,
+  ND6_REACHABLE,
+  ND6_STALE,
+  ND6_DELAY,
+  ND6_PROBE
+};
+
+#if LWIP_ND6_QUEUEING
+/** struct for queueing outgoing packets for unknown address
+  * defined here to be accessed by memp.h
+  */
+struct nd6_q_entry {
+  struct nd6_q_entry *next;
+  struct pbuf *p;
+};
+#endif /* LWIP_ND6_QUEUEING */
+
+/** Neighbor solicitation message header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ns_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t reserved);
+  PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Neighbor advertisement message header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct na_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u8_t flags);
+  PACK_STRUCT_FIELD(u8_t reserved[3]);
+  PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+#define ND6_FLAG_ROUTER      (0x80)
+#define ND6_FLAG_SOLICITED   (0x40)
+#define ND6_FLAG_OVERRIDE    (0x20)
+
+/** Router solicitation message header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct rs_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t reserved);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Router advertisement message header. */
+#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80)
+#define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40)
+#define ND6_RA_FLAG_HOME_AGENT (0x20)
+#define ND6_RA_PREFERENCE_MASK (0x18)
+#define ND6_RA_PREFERENCE_HIGH (0x08)
+#define ND6_RA_PREFERENCE_MEDIUM (0x00)
+#define ND6_RA_PREFERENCE_LOW (0x18)
+#define ND6_RA_PREFERENCE_DISABLED (0x10)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct ra_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u8_t current_hop_limit);
+  PACK_STRUCT_FIELD(u8_t flags);
+  PACK_STRUCT_FIELD(u16_t router_lifetime);
+  PACK_STRUCT_FIELD(u32_t reachable_time);
+  PACK_STRUCT_FIELD(u32_t retrans_timer);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Redirect message header. */
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct redirect_header {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t chksum);
+  PACK_STRUCT_FIELD(u32_t reserved);
+  PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
+  PACK_STRUCT_FIELD(ip6_addr_p_t destination_address);
+  /* Options follow. */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Link-layer address option. */
+#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01)
+#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct lladdr_option {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t length);
+  PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Prefix information option. */
+#define ND6_OPTION_TYPE_PREFIX_INFO (0x03)
+#define ND6_PREFIX_FLAG_ON_LINK (0x80)
+#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40)
+#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20)
+#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct prefix_option {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t length);
+  PACK_STRUCT_FIELD(u8_t prefix_length);
+  PACK_STRUCT_FIELD(u8_t flags);
+  PACK_STRUCT_FIELD(u32_t valid_lifetime);
+  PACK_STRUCT_FIELD(u32_t preferred_lifetime);
+  PACK_STRUCT_FIELD(u8_t reserved2[3]);
+  PACK_STRUCT_FIELD(u8_t site_prefix_length);
+  PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Redirected header option. */
+#define ND6_OPTION_TYPE_REDIR_HDR (0x04)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct redirected_header_option {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t length);
+  PACK_STRUCT_FIELD(u8_t reserved[6]);
+  /* Portion of redirected packet follows. */
+  /* PACK_STRUCT_FIELD(u8_t redirected[8]); */
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** MTU option. */
+#define ND6_OPTION_TYPE_MTU (0x05)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct mtu_option {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t length);
+  PACK_STRUCT_FIELD(u16_t reserved);
+  PACK_STRUCT_FIELD(u32_t mtu);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/** Route information option. */
+#define ND6_OPTION_TYPE_ROUTE_INFO (24)
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
+PACK_STRUCT_BEGIN
+struct route_option {
+  PACK_STRUCT_FIELD(u8_t type);
+  PACK_STRUCT_FIELD(u8_t length);
+  PACK_STRUCT_FIELD(u8_t prefix_length);
+  PACK_STRUCT_FIELD(u8_t preference);
+  PACK_STRUCT_FIELD(u32_t route_lifetime);
+  PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
+
+/* the possible states of an IP address */
+#define IP6_ADDRESS_STATE_INVALID     (0)
+#define IP6_ADDRESS_STATE_VALID       (0x4)
+#define IP6_ADDRESS_STATE_PREFERRED   (0x5) /* includes valid */
+#define IP6_ADDRESS_STATE_DEPRECATED  (0x6) /* includes valid */
+#define IP6_ADDRESS_STATE_TENTATIV    (0x8)
+
+/** 1 second period */
+#define ND6_TMR_INTERVAL 1000
+
+/* Router tables. */
+/* TODO make these static? and entries accessible through API? */
+extern struct nd6_neighbor_cache_entry neighbor_cache[];
+extern struct nd6_destination_cache_entry destination_cache[];
+extern struct nd6_prefix_list_entry prefix_list[];
+extern struct nd6_router_list_entry default_router_list[];
+
+/* Default values, can be updated by a RA message. */
+extern u32_t reachable_time;
+extern u32_t retrans_timer;
+
+#define nd6_init() /* TODO should we init tables? */
+void nd6_tmr(void);
+void nd6_input(struct pbuf *p, struct netif *inp);
+s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif);
+s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif);
+u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif);
+#if LWIP_ND6_QUEUEING
+err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
+#endif /* LWIP_ND6_QUEUEING */
+#if LWIP_ND6_TCP_REACHABILITY_HINTS
+void nd6_reachability_hint(ip6_addr_t * ip6addr);
+#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LWIP_IPV6 */
+
+#endif /* __LWIP_ND6_H__ */
index ad673984d4865a48899f76abd003bab5640b8323..326528a23efd0885ab0dd560593c4c00a0f481e8 100644 (file)
@@ -52,10 +52,10 @@ extern "C" {
  */
 
 /* Flags for netconn_write (u8_t) */
-#define NETCONN_NOFLAG 0x00
-#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
-#define NETCONN_COPY   0x01
-#define NETCONN_MORE   0x02
+#define NETCONN_NOFLAG    0x00
+#define NETCONN_NOCOPY    0x00 /* Only for source code compatibility */
+#define NETCONN_COPY      0x01
+#define NETCONN_MORE      0x02
 #define NETCONN_DONTBLOCK 0x04
 
 /* Flags for struct netconn.flags (u8_t) */
@@ -76,20 +76,41 @@ extern "C" {
 
 
 /* Helpers to process several netconn_types by the same code */
-#define NETCONNTYPE_GROUP(t)    (t&0xF0)
-#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
+#define NETCONNTYPE_GROUP(t)         ((t)&0xF0)
+#define NETCONNTYPE_DATAGRAM(t)      ((t)&0xE0)
+#if LWIP_IPV6
+#define NETCONN_TYPE_IPV6            0x08
+#define NETCONNTYPE_ISIPV6(t)        ((t)&0x08)
+#define NETCONNTYPE_ISUDPLITE(t)     (((t)&0xF7) == NETCONN_UDPLITE)
+#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM)
+#else /* LWIP_IPV6 */
+#define NETCONNTYPE_ISUDPLITE(t)     ((t) == NETCONN_UDPLITE)
+#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
+#endif /* LWIP_IPV6 */
 
 /** Protocol family and type of the netconn */
 enum netconn_type {
-  NETCONN_INVALID    = 0,
+  NETCONN_INVALID     = 0,
   /* NETCONN_TCP Group */
-  NETCONN_TCP        = 0x10,
+  NETCONN_TCP         = 0x10,
+#if LWIP_IPV6
+  NETCONN_TCP_IPV6    = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */,
+#endif /* LWIP_IPV6 */
   /* NETCONN_UDP Group */
-  NETCONN_UDP        = 0x20,
-  NETCONN_UDPLITE    = 0x21,
-  NETCONN_UDPNOCHKSUM= 0x22,
+  NETCONN_UDP         = 0x20,
+  NETCONN_UDPLITE     = 0x21,
+  NETCONN_UDPNOCHKSUM = 0x22,
+#if LWIP_IPV6
+  NETCONN_UDP_IPV6         = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */,
+  NETCONN_UDPLITE_IPV6     = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */,
+  NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */,
+#endif /* LWIP_IPV6 */
   /* NETCONN_RAW Group */
-  NETCONN_RAW        = 0x40
+  NETCONN_RAW         = 0x40
+#if LWIP_IPV6
+  ,
+  NETCONN_RAW_IPV6    = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */
+#endif /* LWIP_IPV6 */
 };
 
 /** Current state of the netconn. Non-TCP netconns are always
@@ -111,13 +132,13 @@ enum netconn_evt {
   NETCONN_EVT_ERROR
 };
 
-#if LWIP_IGMP
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
 /** Used for netconn_join_leave_group() */
 enum netconn_igmp {
   NETCONN_JOIN,
   NETCONN_LEAVE
 };
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 
 /* forward-declare some structs to avoid to include their headers */
 struct ip_pcb;
@@ -168,12 +189,11 @@ struct netconn {
   /** maximum amount of bytes queued in recvmbox
       not used for TCP: adjust TCP_WND instead! */
   int recv_bufsize;
-#endif /* LWIP_SO_RCVBUF */
   /** number of bytes currently in recvmbox to be received,
       tested against recv_bufsize to limit bytes on recvmbox
-      for UDP and RAW
-      @todo: should only be necessary with LWIP_SO_RCVBUF==1 */
+      for UDP and RAW, used for FIONREAD */
   s16_t recv_avail;
+#endif /* LWIP_SO_RCVBUF */
   /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
   u8_t flags;
 #if LWIP_TCP
@@ -209,7 +229,7 @@ struct netconn {
 #define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
 struct
 netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
-                                   netconn_callback callback);
+                                             netconn_callback callback);
 err_t   netconn_delete(struct netconn *conn);
 /** Get the type of a netconn (as enum netconn_type). */
 #define netconn_type(conn) (conn->type)
@@ -221,8 +241,8 @@ err_t   netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
 
 err_t   netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
 err_t   netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
-err_t             netconn_disconnect (struct netconn *conn);
-err_t             netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
+err_t   netconn_disconnect (struct netconn *conn);
+err_t   netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
 #define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
 err_t   netconn_accept(struct netconn *conn, struct netconn **new_conn);
 err_t   netconn_recv(struct netconn *conn, struct netbuf **new_buf);
@@ -231,20 +251,37 @@ void    netconn_recved(struct netconn *conn, u32_t length);
 err_t   netconn_sendto(struct netconn *conn, struct netbuf *buf,
                        ip_addr_t *addr, u16_t port);
 err_t   netconn_send(struct netconn *conn, struct netbuf *buf);
-err_t   netconn_write(struct netconn *conn, const void *dataptr, size_t size,
-                                   u8_t apiflags);
+err_t   netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
+                             u8_t apiflags, size_t *bytes_written);
+#define netconn_write(conn, dataptr, size, apiflags) \
+          netconn_write_partly(conn, dataptr, size, apiflags, NULL)
 err_t   netconn_close(struct netconn *conn);
+err_t   netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
 
-#if LWIP_IGMP
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
 err_t   netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
                                  ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 #if LWIP_DNS
 err_t   netconn_gethostbyname(const char *name, ip_addr_t *addr);
 #endif /* LWIP_DNS */
+#if LWIP_IPV6
+
+#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
+        netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
+#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
+        netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
+#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
+        netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL)
+#if LWIP_IPV6_MLD
+#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \
+        netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\
+        ERR_VAL)
+#endif /* LWIP_IPV6_MLD*/
+#endif /* LWIP_IPV6 */
 
 #define netconn_err(conn)               ((conn)->last_err)
-#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
+#define netconn_recv_bufsize(conn)      ((conn)->recv_bufsize)
 
 /** Set the blocking status of netconn calls (@todo: write/send is missing) */
 #define netconn_set_nonblocking(conn, val)  do { if(val) { \
index aeec5a80f218db3e00c7da585c8dca67e2b71dc4..fca361d98c5d8474daa1c30a99de9c6b88825ad5 100644 (file)
 extern "C" {
 #endif
 
+/* For the netconn API, these values are use as a bitmask! */
+#define NETCONN_SHUT_RD   1
+#define NETCONN_SHUT_WR   2
+#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
+
 /* IP addresses and port numbers are expected to be in
  * the same byte order as in the corresponding pcb.
  */
@@ -75,7 +80,7 @@ struct api_msg_msg {
     } bc;
     /** used for do_getaddr */
     struct {
-      ip_addr_t *ipaddr;
+      ipX_addr_t *ipaddr;
       u16_t *port;
       u8_t local;
     } ad;
@@ -89,14 +94,18 @@ struct api_msg_msg {
     struct {
       u32_t len;
     } r;
-#if LWIP_IGMP
+    /** used for do_close (/shutdown) */
+    struct {
+      u8_t shut;
+    } sd;
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
     /** used for do_join_leave_group */
     struct {
-      ip_addr_t *multiaddr;
-      ip_addr_t *netif_addr;
+      ipX_addr_t *multiaddr;
+      ipX_addr_t *netif_addr;
       enum netconn_igmp join_or_leave;
     } jl;
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 #if TCP_LISTEN_BACKLOG
     struct {
       u8_t backlog;
@@ -144,9 +153,10 @@ void do_recv            ( struct api_msg_msg *msg);
 void do_write           ( struct api_msg_msg *msg);
 void do_getaddr         ( struct api_msg_msg *msg);
 void do_close           ( struct api_msg_msg *msg);
-#if LWIP_IGMP
+void do_shutdown        ( struct api_msg_msg *msg);
+#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
 void do_join_leave_group( struct api_msg_msg *msg);
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
 
 #if LWIP_DNS
 void do_gethostbyname(void *arg);
index 57a6bc0060d91015cc2d38468603a6cb44d7daa9..c9960f37c5185442c715a9f1e8e3fac91b30b9df 100644 (file)
@@ -79,154 +79,154 @@ extern "C" {
 
 #ifdef LWIP_PROVIDE_ERRNO
 
-#define  EPERM     1  /* Operation not permitted */
-#define  ENOENT     2  /* No such file or directory */
-#define  ESRCH     3  /* No such process */
-#define  EINTR     4  /* Interrupted system call */
-#define  EIO     5  /* I/O error */
-#define  ENXIO     6  /* No such device or address */
-#define  E2BIG     7  /* Arg list too long */
-#define  ENOEXEC     8  /* Exec format error */
-#define  EBADF     9  /* Bad file number */
-#define  ECHILD    10  /* No child processes */
-#define  EAGAIN    11  /* Try again */
-#define  ENOMEM    12  /* Out of memory */
-#define  EACCES    13  /* Permission denied */
-#define  EFAULT    14  /* Bad address */
-#define  ENOTBLK    15  /* Block device required */
-#define  EBUSY    16  /* Device or resource busy */
-#define  EEXIST    17  /* File exists */
-#define  EXDEV    18  /* Cross-device link */
-#define  ENODEV    19  /* No such device */
-#define  ENOTDIR    20  /* Not a directory */
-#define  EISDIR    21  /* Is a directory */
-#define  EINVAL    22  /* Invalid argument */
-#define  ENFILE    23  /* File table overflow */
-#define  EMFILE    24  /* Too many open files */
-#define  ENOTTY    25  /* Not a typewriter */
-#define  ETXTBSY    26  /* Text file busy */
-#define  EFBIG    27  /* File too large */
-#define  ENOSPC    28  /* No space left on device */
-#define  ESPIPE    29  /* Illegal seek */
-#define  EROFS    30  /* Read-only file system */
-#define  EMLINK    31  /* Too many links */
-#define  EPIPE    32  /* Broken pipe */
-#define  EDOM    33  /* Math argument out of domain of func */
-#define  ERANGE    34  /* Math result not representable */
-#define  EDEADLK    35  /* Resource deadlock would occur */
-#define  ENAMETOOLONG  36  /* File name too long */
-#define  ENOLCK    37  /* No record locks available */
-#define  ENOSYS    38  /* Function not implemented */
-#define  ENOTEMPTY  39  /* Directory not empty */
-#define  ELOOP    40  /* Too many symbolic links encountered */
+#define  EPERM         1  /* Operation not permitted */
+#define  ENOENT        2  /* No such file or directory */
+#define  ESRCH         3  /* No such process */
+#define  EINTR         4  /* Interrupted system call */
+#define  EIO           5  /* I/O error */
+#define  ENXIO         6  /* No such device or address */
+#define  E2BIG         7  /* Arg list too long */
+#define  ENOEXEC       8  /* Exec format error */
+#define  EBADF         9  /* Bad file number */
+#define  ECHILD       10  /* No child processes */
+#define  EAGAIN       11  /* Try again */
+#define  ENOMEM       12  /* Out of memory */
+#define  EACCES       13  /* Permission denied */
+#define  EFAULT       14  /* Bad address */
+#define  ENOTBLK      15  /* Block device required */
+#define  EBUSY        16  /* Device or resource busy */
+#define  EEXIST       17  /* File exists */
+#define  EXDEV        18  /* Cross-device link */
+#define  ENODEV       19  /* No such device */
+#define  ENOTDIR      20  /* Not a directory */
+#define  EISDIR       21  /* Is a directory */
+#define  EINVAL       22  /* Invalid argument */
+#define  ENFILE       23  /* File table overflow */
+#define  EMFILE       24  /* Too many open files */
+#define  ENOTTY       25  /* Not a typewriter */
+#define  ETXTBSY      26  /* Text file busy */
+#define  EFBIG        27  /* File too large */
+#define  ENOSPC       28  /* No space left on device */
+#define  ESPIPE       29  /* Illegal seek */
+#define  EROFS        30  /* Read-only file system */
+#define  EMLINK       31  /* Too many links */
+#define  EPIPE        32  /* Broken pipe */
+#define  EDOM         33  /* Math argument out of domain of func */
+#define  ERANGE       34  /* Math result not representable */
+#define  EDEADLK      35  /* Resource deadlock would occur */
+#define  ENAMETOOLONG 36  /* File name too long */
+#define  ENOLCK       37  /* No record locks available */
+#define  ENOSYS       38  /* Function not implemented */
+#define  ENOTEMPTY    39  /* Directory not empty */
+#define  ELOOP        40  /* Too many symbolic links encountered */
 #define  EWOULDBLOCK  EAGAIN  /* Operation would block */
-#define  ENOMSG    42  /* No message of desired type */
-#define  EIDRM    43  /* Identifier removed */
-#define  ECHRNG    44  /* Channel number out of range */
-#define  EL2NSYNC  45  /* Level 2 not synchronized */
-#define  EL3HLT    46  /* Level 3 halted */
-#define  EL3RST    47  /* Level 3 reset */
-#define  ELNRNG    48  /* Link number out of range */
-#define  EUNATCH    49  /* Protocol driver not attached */
-#define  ENOCSI    50  /* No CSI structure available */
-#define  EL2HLT    51  /* Level 2 halted */
-#define  EBADE    52  /* Invalid exchange */
-#define  EBADR    53  /* Invalid request descriptor */
-#define  EXFULL    54  /* Exchange full */
-#define  ENOANO    55  /* No anode */
-#define  EBADRQC    56  /* Invalid request code */
-#define  EBADSLT    57  /* Invalid slot */
-
-#define  EDEADLOCK  EDEADLK
-
-#define  EBFONT    59  /* Bad font file format */
-#define  ENOSTR    60  /* Device not a stream */
-#define  ENODATA    61  /* No data available */
-#define  ETIME    62  /* Timer expired */
-#define  ENOSR    63  /* Out of streams resources */
-#define  ENONET    64  /* Machine is not on the network */
-#define  ENOPKG    65  /* Package not installed */
-#define  EREMOTE    66  /* Object is remote */
-#define  ENOLINK    67  /* Link has been severed */
-#define  EADV    68  /* Advertise error */
-#define  ESRMNT    69  /* Srmount error */
-#define  ECOMM    70  /* Communication error on send */
-#define  EPROTO    71  /* Protocol error */
-#define  EMULTIHOP  72  /* Multihop attempted */
-#define  EDOTDOT    73  /* RFS specific error */
-#define  EBADMSG    74  /* Not a data message */
-#define  EOVERFLOW  75  /* Value too large for defined data type */
-#define  ENOTUNIQ  76  /* Name not unique on network */
-#define  EBADFD    77  /* File descriptor in bad state */
-#define  EREMCHG    78  /* Remote address changed */
-#define  ELIBACC    79  /* Can not access a needed shared library */
-#define  ELIBBAD    80  /* Accessing a corrupted shared library */
-#define  ELIBSCN    81  /* .lib section in a.out corrupted */
-#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */
-#define  ELIBEXEC  83  /* Cannot exec a shared library directly */
-#define  EILSEQ    84  /* Illegal byte sequence */
-#define  ERESTART  85  /* Interrupted system call should be restarted */
-#define  ESTRPIPE  86  /* Streams pipe error */
-#define  EUSERS    87  /* Too many users */
-#define  ENOTSOCK  88  /* Socket operation on non-socket */
-#define  EDESTADDRREQ  89  /* Destination address required */
-#define  EMSGSIZE  90  /* Message too long */
-#define  EPROTOTYPE  91  /* Protocol wrong type for socket */
+#define  ENOMSG       42  /* No message of desired type */
+#define  EIDRM        43  /* Identifier removed */
+#define  ECHRNG       44  /* Channel number out of range */
+#define  EL2NSYNC     45  /* Level 2 not synchronized */
+#define  EL3HLT       46  /* Level 3 halted */
+#define  EL3RST       47  /* Level 3 reset */
+#define  ELNRNG       48  /* Link number out of range */
+#define  EUNATCH      49  /* Protocol driver not attached */
+#define  ENOCSI       50  /* No CSI structure available */
+#define  EL2HLT       51  /* Level 2 halted */
+#define  EBADE        52  /* Invalid exchange */
+#define  EBADR        53  /* Invalid request descriptor */
+#define  EXFULL       54  /* Exchange full */
+#define  ENOANO       55  /* No anode */
+#define  EBADRQC      56  /* Invalid request code */
+#define  EBADSLT      57  /* Invalid slot */
+
+#define  EDEADLOCK    EDEADLK
+
+#define  EBFONT       59  /* Bad font file format */
+#define  ENOSTR       60  /* Device not a stream */
+#define  ENODATA      61  /* No data available */
+#define  ETIME        62  /* Timer expired */
+#define  ENOSR        63  /* Out of streams resources */
+#define  ENONET       64  /* Machine is not on the network */
+#define  ENOPKG       65  /* Package not installed */
+#define  EREMOTE      66  /* Object is remote */
+#define  ENOLINK      67  /* Link has been severed */
+#define  EADV         68  /* Advertise error */
+#define  ESRMNT       69  /* Srmount error */
+#define  ECOMM        70  /* Communication error on send */
+#define  EPROTO       71  /* Protocol error */
+#define  EMULTIHOP    72  /* Multihop attempted */
+#define  EDOTDOT      73  /* RFS specific error */
+#define  EBADMSG      74  /* Not a data message */
+#define  EOVERFLOW    75  /* Value too large for defined data type */
+#define  ENOTUNIQ     76  /* Name not unique on network */
+#define  EBADFD       77  /* File descriptor in bad state */
+#define  EREMCHG      78  /* Remote address changed */
+#define  ELIBACC      79  /* Can not access a needed shared library */
+#define  ELIBBAD      80  /* Accessing a corrupted shared library */
+#define  ELIBSCN      81  /* .lib section in a.out corrupted */
+#define  ELIBMAX      82  /* Attempting to link in too many shared libraries */
+#define  ELIBEXEC     83  /* Cannot exec a shared library directly */
+#define  EILSEQ       84  /* Illegal byte sequence */
+#define  ERESTART     85  /* Interrupted system call should be restarted */
+#define  ESTRPIPE     86  /* Streams pipe error */
+#define  EUSERS       87  /* Too many users */
+#define  ENOTSOCK     88  /* Socket operation on non-socket */
+#define  EDESTADDRREQ 89  /* Destination address required */
+#define  EMSGSIZE     90  /* Message too long */
+#define  EPROTOTYPE   91  /* Protocol wrong type for socket */
 #define  ENOPROTOOPT  92  /* Protocol not available */
-#define  EPROTONOSUPPORT  93  /* Protocol not supported */
-#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */
-#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */
-#define  EPFNOSUPPORT  96  /* Protocol family not supported */
-#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */
-#define  EADDRINUSE  98  /* Address already in use */
-#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */
-#define  ENETDOWN  100  /* Network is down */
-#define  ENETUNREACH  101  /* Network is unreachable */
-#define  ENETRESET  102  /* Network dropped connection because of reset */
-#define  ECONNABORTED  103  /* Software caused connection abort */
-#define  ECONNRESET  104  /* Connection reset by peer */
-#define  ENOBUFS    105  /* No buffer space available */
-#define  EISCONN    106  /* Transport endpoint is already connected */
-#define  ENOTCONN  107  /* Transport endpoint is not connected */
-#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */
-#define  ETOOMANYREFS  109  /* Too many references: cannot splice */
-#define  ETIMEDOUT  110  /* Connection timed out */
-#define  ECONNREFUSED  111  /* Connection refused */
-#define  EHOSTDOWN  112  /* Host is down */
-#define  EHOSTUNREACH  113  /* No route to host */
-#define  EALREADY  114  /* Operation already in progress */
-#define  EINPROGRESS  115  /* Operation now in progress */
-#define  ESTALE    116  /* Stale NFS file handle */
-#define  EUCLEAN    117  /* Structure needs cleaning */
-#define  ENOTNAM    118  /* Not a XENIX named type file */
-#define  ENAVAIL    119  /* No XENIX semaphores available */
-#define  EISNAM    120  /* Is a named type file */
-#define  EREMOTEIO  121  /* Remote I/O error */
-#define  EDQUOT    122  /* Quota exceeded */
-
-#define  ENOMEDIUM  123  /* No medium found */
-#define  EMEDIUMTYPE  124  /* Wrong medium type */
-
-
-#define ENSROK    0 /* DNS server returned answer with no data */
-#define ENSRNODATA  160 /* DNS server returned answer with no data */
-#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
-#define ENSRSERVFAIL 162  /* DNS server returned general failure */
-#define ENSRNOTFOUND 163  /* Domain name not found */
-#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */
-#define ENSRREFUSED 165 /* DNS server refused query */
-#define ENSRBADQUERY 166  /* Misformatted DNS query */
-#define ENSRBADNAME 167 /* Misformatted domain name */
-#define ENSRBADFAMILY 168 /* Unsupported address family */
-#define ENSRBADRESP 169 /* Misformatted DNS reply */
-#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
-#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
-#define ENSROF    172 /* End of file */
-#define ENSRFILE  173 /* Error reading file */
-#define ENSRNOMEM 174 /* Out of memory */
-#define ENSRDESTRUCTION 175 /* Application terminated lookup */
+#define  EPROTONOSUPPORT 93  /* Protocol not supported */
+#define  ESOCKTNOSUPPORT 94  /* Socket type not supported */
+#define  EOPNOTSUPP      95  /* Operation not supported on transport endpoint */
+#define  EPFNOSUPPORT    96  /* Protocol family not supported */
+#define  EAFNOSUPPORT    97  /* Address family not supported by protocol */
+#define  EADDRINUSE      98  /* Address already in use */
+#define  EADDRNOTAVAIL   99  /* Cannot assign requested address */
+#define  ENETDOWN       100  /* Network is down */
+#define  ENETUNREACH    101  /* Network is unreachable */
+#define  ENETRESET      102  /* Network dropped connection because of reset */
+#define  ECONNABORTED   103  /* Software caused connection abort */
+#define  ECONNRESET     104  /* Connection reset by peer */
+#define  ENOBUFS        105  /* No buffer space available */
+#define  EISCONN        106  /* Transport endpoint is already connected */
+#define  ENOTCONN       107  /* Transport endpoint is not connected */
+#define  ESHUTDOWN      108  /* Cannot send after transport endpoint shutdown */
+#define  ETOOMANYREFS   109  /* Too many references: cannot splice */
+#define  ETIMEDOUT      110  /* Connection timed out */
+#define  ECONNREFUSED   111  /* Connection refused */
+#define  EHOSTDOWN      112  /* Host is down */
+#define  EHOSTUNREACH   113  /* No route to host */
+#define  EALREADY       114  /* Operation already in progress */
+#define  EINPROGRESS    115  /* Operation now in progress */
+#define  ESTALE         116  /* Stale NFS file handle */
+#define  EUCLEAN        117  /* Structure needs cleaning */
+#define  ENOTNAM        118  /* Not a XENIX named type file */
+#define  ENAVAIL        119  /* No XENIX semaphores available */
+#define  EISNAM         120  /* Is a named type file */
+#define  EREMOTEIO      121  /* Remote I/O error */
+#define  EDQUOT         122  /* Quota exceeded */
+
+#define  ENOMEDIUM      123  /* No medium found */
+#define  EMEDIUMTYPE    124  /* Wrong medium type */
+
+
+#define ENSROK                    0 /* DNS server returned answer with no data */
+#define ENSRNODATA              160 /* DNS server returned answer with no data */
+#define ENSRFORMERR             161 /* DNS server claims query was misformatted */
+#define ENSRSERVFAIL            162 /* DNS server returned general failure */
+#define ENSRNOTFOUND            163 /* Domain name not found */
+#define ENSRNOTIMP              164 /* DNS server does not implement requested operation */
+#define ENSRREFUSED             165 /* DNS server refused query */
+#define ENSRBADQUERY            166 /* Misformatted DNS query */
+#define ENSRBADNAME             167 /* Misformatted domain name */
+#define ENSRBADFAMILY           168 /* Unsupported address family */
+#define ENSRBADRESP             169 /* Misformatted DNS reply */
+#define ENSRCONNREFUSED         170 /* Could not contact DNS servers */
+#define ENSRTIMEOUT             171 /* Timeout while contacting DNS servers */
+#define ENSROF                  172 /* End of file */
+#define ENSRFILE                173 /* Error reading file */
+#define ENSRNOMEM               174 /* Out of memory */
+#define ENSRDESTRUCTION         175 /* Application terminated lookup */
 #define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */
-#define ENSRCNAMELOOP 177 /* Domain name is too long */
+#define ENSRCNAMELOOP           177 /* Domain name is too long */
 
 #ifndef errno
 extern int errno;
index d8359ea3a53f32bfc8d49c63754a157ecc50ce4a..0fe041396fcea28411e62b48e500c8c1512c857d 100644 (file)
@@ -33,6 +33,7 @@
 #define __LWIP_DEBUG_H__
 
 #include "lwip/arch.h"
+#include "lwip/opt.h"
 
 /** lower two bits indicate debug level
  * - 0 all
index 1cc7ac12fe967382e8f905d653a9d5ed98468803..32d93381d127b3bad1fd5a62f76ae770119bb1e5 100644 (file)
@@ -80,10 +80,10 @@ struct dhcp_msg
   PACK_STRUCT_FIELD(u32_t xid);
   PACK_STRUCT_FIELD(u16_t secs);
   PACK_STRUCT_FIELD(u16_t flags);
-  PACK_STRUCT_FIELD(ip_addr_t ciaddr);
-  PACK_STRUCT_FIELD(ip_addr_t yiaddr);
-  PACK_STRUCT_FIELD(ip_addr_t siaddr);
-  PACK_STRUCT_FIELD(ip_addr_t giaddr);
+  PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
+  PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
+  PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
+  PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
   PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
   PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
   PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
@@ -106,6 +106,9 @@ PACK_STRUCT_END
 #endif
 
 void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
+/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
+#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
+void dhcp_cleanup(struct netif *netif);
 /** start DHCP configuration */
 err_t dhcp_start(struct netif *netif);
 /** enforce early lease renewal (not needed normally)*/
@@ -144,45 +147,45 @@ void dhcp_fine_tmr(void);
 #define DHCP_CHADDR_OFS   28
 #define DHCP_SNAME_OFS    44
 #define DHCP_FILE_OFS     108
-#define DHCP_MSG_LEN 236
+#define DHCP_MSG_LEN      236
 
 #define DHCP_COOKIE_OFS   DHCP_MSG_LEN
 #define DHCP_OPTIONS_OFS  (DHCP_MSG_LEN + 4)
 
-#define DHCP_CLIENT_PORT 68  
-#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT  68  
+#define DHCP_SERVER_PORT  67
 
 /** DHCP client states */
 #define DHCP_OFF          0
-#define DHCP_REQUESTING 1
-#define DHCP_INIT 2
-#define DHCP_REBOOTING 3
-#define DHCP_REBINDING 4
-#define DHCP_RENEWING 5
-#define DHCP_SELECTING 6
-#define DHCP_INFORMING 7
-#define DHCP_CHECKING 8
-#define DHCP_PERMANENT 9
-#define DHCP_BOUND 10
+#define DHCP_REQUESTING   1
+#define DHCP_INIT         2
+#define DHCP_REBOOTING    3
+#define DHCP_REBINDING    4
+#define DHCP_RENEWING     5
+#define DHCP_SELECTING    6
+#define DHCP_INFORMING    7
+#define DHCP_CHECKING     8
+#define DHCP_PERMANENT    9
+#define DHCP_BOUND        10
 /** not yet implemented #define DHCP_RELEASING 11 */
-#define DHCP_BACKING_OFF 12
+#define DHCP_BACKING_OFF  12
 
 /** AUTOIP cooperatation flags */
-#define DHCP_AUTOIP_COOP_STATE_OFF 0
-#define DHCP_AUTOIP_COOP_STATE_ON 1
+#define DHCP_AUTOIP_COOP_STATE_OFF  0
+#define DHCP_AUTOIP_COOP_STATE_ON   1
  
-#define DHCP_BOOTREQUEST 1
-#define DHCP_BOOTREPLY 2
+#define DHCP_BOOTREQUEST  1
+#define DHCP_BOOTREPLY    2
 
 /** DHCP message types */
 #define DHCP_DISCOVER 1
-#define DHCP_OFFER 2
-#define DHCP_REQUEST 3
-#define DHCP_DECLINE 4
-#define DHCP_ACK 5
-#define DHCP_NAK 6
-#define DHCP_RELEASE 7
-#define DHCP_INFORM 8
+#define DHCP_OFFER    2
+#define DHCP_REQUEST  3
+#define DHCP_DECLINE  4
+#define DHCP_ACK      5
+#define DHCP_NAK      6
+#define DHCP_RELEASE  7
+#define DHCP_INFORM   8
 
 /** DHCP hardware type, currently only ethernet is supported */
 #define DHCP_HTYPE_ETH 1
index 6042bf75b0e7e3ffe9eaf99c1f401bd35ebf1c7a..6c7d9b07399f3f91f8f7fba8a4ba6dc8470ec0bc 100644 (file)
 
 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** DNS timer period */
 #define DNS_TMR_INTERVAL          1000
 
@@ -111,6 +115,10 @@ int            dns_local_removehost(const char *hostname, const ip_addr_t *addr)
 err_t          dns_local_addhost(const char *hostname, const ip_addr_t *addr);
 #endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LWIP_DNS */
 
 #endif /* __LWIP_DNS_H__ */
index b35ae75f844ffd8c9ac6b798e48721408ce31ddd..ac907729fcdbe983451924662a333475078d25de 100644 (file)
@@ -57,20 +57,19 @@ typedef s8_t err_t;
 #define ERR_INPROGRESS -5    /* Operation in progress    */
 #define ERR_VAL        -6    /* Illegal value.           */
 #define ERR_WOULDBLOCK -7    /* Operation would block.   */
+#define ERR_USE        -8    /* Address in use.          */
+#define ERR_ISCONN     -9    /* Already connected.       */
 
-#define ERR_IS_FATAL(e) ((e) < ERR_VAL)
+#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
 
-#define ERR_ABRT       -   /* Connection aborted.      */
-#define ERR_RST        -   /* Connection reset.        */
-#define ERR_CLSD       -10   /* Connection closed.       */
-#define ERR_CONN       -11   /* Not connected.           */
+#define ERR_ABRT       -10   /* Connection aborted.      */
+#define ERR_RST        -11   /* Connection reset.        */
+#define ERR_CLSD       -12   /* Connection closed.       */
+#define ERR_CONN       -13   /* Not connected.           */
 
-#define ERR_ARG        -12   /* Illegal argument.        */
+#define ERR_ARG        -14   /* Illegal argument.        */
 
-#define ERR_USE        -13   /* Address in use.          */
-
-#define ERR_IF         -14   /* Low-level netif error    */
-#define ERR_ISCONN     -15   /* Already connected.       */
+#define ERR_IF         -15   /* Low-level netif error    */
 
 
 #ifdef LWIP_DEBUG
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/inet_chksum.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/inet_chksum.h
new file mode 100644 (file)
index 0000000..e168788
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_INET_CHKSUM_H__
+#define __LWIP_INET_CHKSUM_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+
+/** Swap the bytes in an u16_t: much like htons() for little-endian */
+#ifndef SWAP_BYTES_IN_WORD
+#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
+/* little endian and PLATFORM_BYTESWAP defined */
+#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
+#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
+/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
+#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
+#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
+#endif /* SWAP_BYTES_IN_WORD */
+
+/** Split an u32_t in two u16_ts and add them up */
+#ifndef FOLD_U32T
+#define FOLD_U32T(u)          (((u) >> 16) + ((u) & 0x0000ffffUL))
+#endif
+
+#if LWIP_CHECKSUM_ON_COPY
+/** Function-like macro: same as MEMCPY but returns the checksum of copied data
+    as u16_t */
+#ifndef LWIP_CHKSUM_COPY
+#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
+#ifndef LWIP_CHKSUM_COPY_ALGORITHM
+#define LWIP_CHKSUM_COPY_ALGORITHM 1
+#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
+#endif /* LWIP_CHKSUM_COPY */
+#else /* LWIP_CHECKSUM_ON_COPY */
+#define LWIP_CHKSUM_COPY_ALGORITHM 0
+#endif /* LWIP_CHECKSUM_ON_COPY */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+u16_t inet_chksum(void *dataptr, u16_t len);
+u16_t inet_chksum_pbuf(struct pbuf *p);
+u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
+       ip_addr_t *src, ip_addr_t *dest);
+u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto,
+       u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest);
+#if LWIP_CHKSUM_COPY_ALGORITHM
+u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
+#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
+
+#if LWIP_IPV6
+u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
+       ip6_addr_t *src, ip6_addr_t *dest);
+u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
+       u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest);
+
+#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
+  ((isipv6) ? \
+  ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
+  inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest)))
+#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
+  ((isipv6) ? \
+  ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
+  inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest)))
+
+#else /* LWIP_IPV6 */
+
+#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
+  inet_chksum_pseudo(p, proto, proto_len, src, dest)
+#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
+  inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest)
+
+#endif /* LWIP_IPV6 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_INET_H__ */
+
index 94897d256153c7f2c1b06f3e424568ac787dfc58..4e2e2856534881c178b161c3296f6e13f342501d 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
 /** x.X.x: Minor version of the stack */
 #define LWIP_VERSION_MINOR      4U
 /** x.x.X: Revision of the stack */
-#define LWIP_VERSION_REVISION   0U
+#define LWIP_VERSION_REVISION   1U
 /** For release candidates, this is set to 1..254
   * For official releases, this is set to 255 (LWIP_RC_RELEASE)
   * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip.h
new file mode 100644 (file)
index 0000000..6de95b1
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP_H__
+#define __LWIP_IP_H__
+
+#include "lwip/opt.h"
+
+#include "lwip/def.h"
+#include "lwip/pbuf.h"
+#include "lwip/ip_addr.h"
+#include "lwip/err.h"
+#include "lwip/netif.h"
+#include "lwip/ip4.h"
+#include "lwip/ip6.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This is passed as the destination address to ip_output_if (not
+   to ip_output), meaning that an IP header already is constructed
+   in the pbuf. This is used when TCP retransmits. */
+#ifdef IP_HDRINCL
+#undef IP_HDRINCL
+#endif /* IP_HDRINCL */
+#define IP_HDRINCL  NULL
+
+#if LWIP_NETIF_HWADDRHINT
+#define IP_PCB_ADDRHINT ;u8_t addr_hint
+#else
+#define IP_PCB_ADDRHINT
+#endif /* LWIP_NETIF_HWADDRHINT */
+
+#if LWIP_IPV6
+#define IP_PCB_ISIPV6_MEMBER  u8_t isipv6;
+#define IP_PCB_IPVER_EQ(pcb1, pcb2)   ((pcb1)->isipv6 == (pcb2)->isipv6)
+#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \
+                                       ((pcb)->isipv6 != 0) : \
+                                       ((pcb)->isipv6 == 0))
+#define PCB_ISIPV6(pcb) ((pcb)->isipv6)
+#else
+#define IP_PCB_ISIPV6_MEMBER
+#define IP_PCB_IPVER_EQ(pcb1, pcb2)   1
+#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1
+#define PCB_ISIPV6(pcb)            0
+#endif /* LWIP_IPV6 */
+
+/* This is the common part of all PCB types. It needs to be at the
+   beginning of a PCB type definition. It is located here so that
+   changes to this common part are made in one location instead of
+   having to change all PCB structs. */
+#define IP_PCB \
+  IP_PCB_ISIPV6_MEMBER \
+  /* ip addresses in network byte order */ \
+  ipX_addr_t local_ip; \
+  ipX_addr_t remote_ip; \
+   /* Socket options */  \
+  u8_t so_options;      \
+   /* Type Of Service */ \
+  u8_t tos;              \
+  /* Time To Live */     \
+  u8_t ttl               \
+  /* link layer address resolution hint */ \
+  IP_PCB_ADDRHINT
+
+struct ip_pcb {
+/* Common members of all PCB types */
+  IP_PCB;
+};
+
+/*
+ * Option flags per-socket. These are the same like SO_XXX.
+ */
+/*#define SOF_DEBUG       0x01U     Unimplemented: turn on debugging info recording */
+#define SOF_ACCEPTCONN    0x02U  /* socket has had listen() */
+#define SOF_REUSEADDR     0x04U  /* allow local address reuse */
+#define SOF_KEEPALIVE     0x08U  /* keep connections alive */
+/*#define SOF_DONTROUTE   0x10U     Unimplemented: just use interface addresses */
+#define SOF_BROADCAST     0x20U  /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
+/*#define SOF_USELOOPBACK 0x40U     Unimplemented: bypass hardware when possible */
+#define SOF_LINGER        0x80U  /* linger on close if data present */
+/*#define SOF_OOBINLINE   0x0100U     Unimplemented: leave received OOB data in line */
+/*#define SOF_REUSEPORT   0x0200U     Unimplemented: allow local address & port reuse */
+
+/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
+#define SOF_INHERITED   (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
+
+/* Global variables of this module, kept in a struct for efficient access using base+index. */
+struct ip_globals
+{
+  /** The interface that provided the packet for the current callback invocation. */
+  struct netif *current_netif;
+  /** Header of the input packet currently being processed. */
+  const struct ip_hdr *current_ip4_header;
+#if LWIP_IPV6
+  /** Header of the input IPv6 packet currently being processed. */
+  const struct ip6_hdr *current_ip6_header;
+#endif /* LWIP_IPV6 */
+  /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */
+  u16_t current_ip_header_tot_len;
+  /** Source IP address of current_header */
+  ipX_addr_t current_iphdr_src;
+  /** Destination IP address of current_header */
+  ipX_addr_t current_iphdr_dest;
+};
+extern struct ip_globals ip_data;
+
+
+/** Get the interface that received the current packet.
+ * This function must only be called from a receive callback (udp_recv,
+ * raw_recv, tcp_accept). It will return NULL otherwise. */
+#define ip_current_netif()      (ip_data.current_netif)
+/** Get the IP header of the current packet.
+ * This function must only be called from a receive callback (udp_recv,
+ * raw_recv, tcp_accept). It will return NULL otherwise. */
+#define ip_current_header()     (ip_data.current_ip4_header)
+/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */
+#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len)
+/** Source IP address of current_header */
+#define ipX_current_src_addr()   (&ip_data.current_iphdr_src)
+/** Destination IP address of current_header */
+#define ipX_current_dest_addr()  (&ip_data.current_iphdr_dest)
+
+#if LWIP_IPV6
+/** Get the IPv6 header of the current packet.
+ * This function must only be called from a receive callback (udp_recv,
+ * raw_recv, tcp_accept). It will return NULL otherwise. */
+#define ip6_current_header()      (ip_data.current_ip6_header)
+/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */
+#define ip_current_is_v6()        (ip6_current_header() != NULL)
+/** Source IPv6 address of current_header */
+#define ip6_current_src_addr()    (ipX_2_ip6(&ip_data.current_iphdr_src))
+/** Destination IPv6 address of current_header */
+#define ip6_current_dest_addr()   (ipX_2_ip6(&ip_data.current_iphdr_dest))
+/** Get the transport layer protocol */
+#define ip_current_header_proto() (ip_current_is_v6() ? \
+                                   IP6H_NEXTH(ip6_current_header()) :\
+                                   IPH_PROTO(ip_current_header()))
+/** Get the transport layer header */
+#define ipX_next_header_ptr()     ((void*)((ip_current_is_v6() ? \
+  (u8_t*)ip6_current_header() : (u8_t*)ip_current_header())  + ip_current_header_tot_len()))
+
+/** Set an IP_PCB to IPv6 (IPv4 is the default) */
+#define ip_set_v6(pcb, val)       do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0)
+
+/** Source IP4 address of current_header */
+#define ip_current_src_addr()     (ipX_2_ip(&ip_data.current_iphdr_src))
+/** Destination IP4 address of current_header */
+#define ip_current_dest_addr()    (ipX_2_ip(&ip_data.current_iphdr_dest))
+
+#else /* LWIP_IPV6 */
+
+/** Always returns FALSE when only supporting IPv4 */
+#define ip_current_is_v6()        0
+/** Get the transport layer protocol */
+#define ip_current_header_proto() IPH_PROTO(ip_current_header())
+/** Get the transport layer header */
+#define ipX_next_header_ptr()     ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len()))
+/** Source IP4 address of current_header */
+#define ip_current_src_addr()     (&ip_data.current_iphdr_src)
+/** Destination IP4 address of current_header */
+#define ip_current_dest_addr()    (&ip_data.current_iphdr_dest)
+
+#endif /* LWIP_IPV6 */
+
+/** Union source address of current_header */
+#define ipX_current_src_addr()    (&ip_data.current_iphdr_src)
+/** Union destination address of current_header */
+#define ipX_current_dest_addr()   (&ip_data.current_iphdr_dest)
+
+#if LWIP_IPV6
+#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
+        ((isipv6) ? \
+        ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \
+        ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto))
+#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
+        ((isipv6) ? \
+        ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \
+        ip_output_if(p, (src), (dest), ttl, tos, proto, netif))
+#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
+        ((isipv6) ? \
+        ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \
+        ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint))
+#define ipX_route(isipv6, src, dest) \
+        ((isipv6) ? \
+        ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \
+        ip_route(ipX_2_ip(dest)))
+#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
+        ((isipv6) ? \
+        ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \
+        ip_netif_get_local_ipX(netif))
+#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p))
+#else /* LWIP_IPV6 */
+#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
+        ip_output(p, src, dest, ttl, tos, proto)
+#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
+        ip_output_if(p, src, dest, ttl, tos, proto, netif)
+#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
+        ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
+#define ipX_route(isipv6, src, dest) \
+        ip_route(ipX_2_ip(dest))
+#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
+        ip_netif_get_local_ipX(netif)
+#define ipX_debug_print(is_ipv6, p) ip_debug_print(p)
+#endif /* LWIP_IPV6 */
+
+#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \
+  (netif) = ipX_route(isipv6, src, dest); \
+  (ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \
+}while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_H__ */
+
+
diff --git a/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip_addr.h b/l4/pkg/ankh/lib/lwip/lib/contrib/src/include/lwip/ip_addr.h
new file mode 100644 (file)
index 0000000..9690bf8
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+ * 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. 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 BY THE AUTHOR ``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 AUTHOR 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 file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __LWIP_IP_ADDR_H__
+#define __LWIP_IP_ADDR_H__
+
+#include "lwip/opt.h"
+#include "lwip/def.h"
+
+#include "lwip/ip4_addr.h"
+#include "lwip/ip6_addr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if LWIP_IPV6
+/* A union struct for both IP version's addresses. */
+typedef union {
+  ip_addr_t ip4;
+  ip6_addr_t ip6;
+} ipX_addr_t;
+
+/** These functions only exist for type-safe conversion from ip_addr_t to
+    ip6_addr_t and back */
+#if LWIP_ALLOW_STATIC_FN_IN_HEADER
+static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr)
+{ return (ip6_addr_t*)ipaddr;}
+static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr)
+{ return (ip_addr_t*)ip6addr; }
+static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr)
+{ return (ipX_addr_t*)ipaddr; }
+static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr)
+{ return (ipX_addr_t*)ip6addr; }
+#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */
+#define ip_2_ip6(ipaddr)   ((ip6_addr_t*)(ipaddr))
+#define ip6_2_ip(ip6addr)  ((ip_addr_t*)(ip6addr))
+#define ip_2_ipX(ipaddr)   ((ipX_addr_t*)ipaddr)
+#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr)
+#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/
+#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6))
+#define ipX_2_ip(ipaddr)   (&((ipaddr)->ip4))
+
+#define ipX_addr_copy(is_ipv6, dest, src)      do{if(is_ipv6){ \
+  ip6_addr_copy((dest).ip6, (src).ip6); }else{ \
+  ip_addr_copy((dest).ip4, (src).ip4); }}while(0)
+#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \
+  ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \
+  ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0)
+#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \
+  ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \
+  ip_addr_set(ipX_2_ip(dest), src); }}while(0)
+#define ipX_addr_set_zero(is_ipv6, ipaddr)     do{if(is_ipv6){ \
+  ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \
+  ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0)
+#define ipX_addr_set_any(is_ipv6, ipaddr)      do{if(is_ipv6){ \
+  ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \
+  ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0)
+#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \
+  ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \
+  ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0)
+#define ipX_addr_set_hton(is_ipv6, dest, src)  do{if(is_ipv6){ \
+  ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \
+  ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0)
+#define ipX_addr_cmp(is_ipv6, addr1, addr2)    ((is_ipv6) ? \
+  ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \
+  ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2)))
+#define ipX_addr_isany(is_ipv6, ipaddr)        ((is_ipv6) ? \
+  ip6_addr_isany(ipX_2_ip6(ipaddr)) : \
+  ip_addr_isany(ipX_2_ip(ipaddr)))
+#define ipX_addr_ismulticast(is_ipv6, ipaddr)  ((is_ipv6) ? \
+  ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \
+  ip_addr_ismulticast(ipX_2_ip(ipaddr)))
+#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \
+  ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \
+  ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0)
+
+#else /* LWIP_IPV6 */
+
+typedef ip_addr_t ipX_addr_t;
+#define ipX_2_ip(ipaddr) (ipaddr)
+#define ip_2_ipX(ipaddr) (ipaddr)
+
+#define ipX_addr_copy(is_ipv6, dest, src)       ip_addr_copy(dest, src)
+#define ipX_addr_set(is_ipv6, dest, src)        ip_addr_set(dest, src)
+#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src)
+#define ipX_addr_set_zero(is_ipv6, ipaddr)      ip_addr_set_zero(ipaddr)
+#define ipX_addr_set_any(is_ipv6, ipaddr)       ip_addr_set_any(ipaddr)
+#define ipX_addr_set_loopback(is_ipv6, ipaddr)  ip_addr_set_loopback(ipaddr)
+#define ipX_addr_set_hton(is_ipv6, dest, src)   ip_addr_set_hton(dest, src)
+#define ipX_addr_cmp(is_ipv6, addr1, addr2)     ip_addr_cmp(addr1, addr2)
+#define ipX_addr_isany(is_ipv6, ipaddr)         ip_addr_isany(ipaddr)
+#define ipX_addr_ismulticast(is_ipv6, ipaddr)   ip_addr_ismulticast(ipaddr)
+#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr)
+
+#endif /* LWIP_IPV6 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP_IP_ADDR_H__ */
index e7d8b8baf09485c4dd84c642497edf8330fa8828..9507c0aec4123ff08a302309d5915bb3e66cc684 100644 (file)
@@ -68,7 +68,7 @@ typedef size_t mem_size_t;
 /* MEM_SIZE would have to be aligned, but using 64000 here instead of
  * 65535 leaves some room for alignment...
  */
-#if MEM_SIZE > 64000l
+#if MEM_SIZE > 64000L
 typedef u32_t mem_size_t;
 #define MEM_SIZE_F U32_F
 #else
index c64f7b8835adabd0a99671b755db09d468431cad..e7b90f29a9b189f1480771094c300d6cf8daefb0 100644 (file)
@@ -47,6 +47,9 @@ LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),
 #if IP_REASSEMBLY
 LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA")
 #endif /* IP_REASSEMBLY */
+#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG
+LWIP_MEMPOOL(FRAG_PBUF,      MEMP_NUM_FRAG_PBUF,       sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
+#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
 
 #if LWIP_NETCONN
 LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF")
@@ -68,7 +71,9 @@ LWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_en
 LWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group),     "IGMP_GROUP")
 #endif /* LWIP_IGMP */
 
+#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
 LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT")
+#endif /* LWIP_TIMERS */
 
 #if LWIP_SNMP
 LWIP_MEMPOOL(SNMP_ROOTNODE,  MEMP_NUM_SNMP_ROOTNODE,   sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
@@ -86,6 +91,19 @@ LWIP_MEMPOOL(LOCALHOSTLIST,  MEMP_NUM_LOCALHOSTLIST,   LOCALHOSTLIST_ELEM_SIZE,
 LWIP_MEMPOOL(PPPOE_IF,      MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc),    "PPPOE_IF")
 #endif /* PPP_SUPPORT && PPPOE_SUPPORT */
 
+#if LWIP_IPV6 && LWIP_ND6_QUEUEING
+LWIP_MEMPOOL(ND6_QUEUE,      MEMP_NUM_ND6_QUEUE,       sizeof(struct nd6_q_entry), "ND6_QUEUE")
+#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */
+
+#if LWIP_IPV6 && LWIP_IPV6_REASS
+LWIP_MEMPOOL(IP6_REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip6_reassdata),   "IP6_REASSDATA")
+#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
+
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+LWIP_MEMPOOL(MLD6_GROUP,     MEMP_NUM_MLD6_GROUP,      sizeof(struct mld_group),     "MLD6_GROUP")
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
+
+
 /*
  * A list of pools of pbuf's used by LWIP.
  *
index 4babb9070d94fe86bc4ee818b0a7b9c08583c481..d12fe270999385a0a98a30600ec00c4a4438ec88 100644 (file)
@@ -35,6 +35,7 @@
 #include "lwip/opt.h"
 #include "lwip/pbuf.h"
 #include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,7 +48,7 @@ extern "C" {
 
 struct netbuf {
   struct pbuf *p, *ptr;
-  ip_addr_t *addr;
+  ipX_addr_t addr;
   u16_t port;
 #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
 #if LWIP_CHECKSUM_ON_COPY
@@ -55,7 +56,7 @@ struct netbuf {
 #endif /* LWIP_CHECKSUM_ON_COPY */
   u16_t toport_chksum;
 #if LWIP_NETBUF_RECVINFO
-  ip_addr_t *toaddr;
+  ipX_addr_t toaddr;
 #endif /* LWIP_NETBUF_RECVINFO */
 #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
 };
@@ -66,12 +67,12 @@ void              netbuf_delete   (struct netbuf *buf);
 void *            netbuf_alloc    (struct netbuf *buf, u16_t size);
 void              netbuf_free     (struct netbuf *buf);
 err_t             netbuf_ref      (struct netbuf *buf,
-           const void *dataptr, u16_t size);
+                                   const void *dataptr, u16_t size);
 void              netbuf_chain    (struct netbuf *head,
            struct netbuf *tail);
 
 err_t             netbuf_data     (struct netbuf *buf,
-           void **dataptr, u16_t *len);
+                                   void **dataptr, u16_t *len);
 s8_t              netbuf_next     (struct netbuf *buf);
 void              netbuf_first    (struct netbuf *buf);
 
@@ -81,10 +82,12 @@ void              netbuf_first    (struct netbuf *buf);
 #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
 #define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
 #define netbuf_len(buf)              ((buf)->p->tot_len)
-#define netbuf_fromaddr(buf)         ((buf)->addr)
+#define netbuf_fromaddr(buf)         (ipX_2_ip(&((buf)->addr)))
+#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr)
 #define netbuf_fromport(buf)         ((buf)->port)
 #if LWIP_NETBUF_RECVINFO
-#define netbuf_destaddr(buf)         ((buf)->toaddr)
+#define netbuf_destaddr(buf)         (ipX_2_ip(&((buf)->toaddr)))
+#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr)
 #define netbuf_destport(buf)         (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
 #endif /* LWIP_NETBUF_RECVINFO */
 #if LWIP_CHECKSUM_ON_COPY
@@ -92,6 +95,16 @@ void              netbuf_first    (struct netbuf *buf);
                                             (buf)->toport_chksum = chksum; } while(0)
 #endif /* LWIP_CHECKSUM_ON_COPY */
 
+#if LWIP_IPV6
+#define netbuf_fromaddr_ip6(buf)         (ipX_2_ip6(&((buf)->addr)))
+#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr)
+#define netbuf_destaddr_ip6(buf)         (ipX_2_ip6(&((buf)->toaddr)))
+#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr)
+#endif /* LWIP_IPV6 */
+
+#define netbuf_fromaddr_ipX(buf)         (&((buf)->addr))
+#define netbuf_destaddr_ipX(buf)         (&((buf)->toaddr))
+
 #ifdef __cplusplus
 }
 #endif
index 54a1eb878528ba6687f9158e39d9bf8298d54fa3..7587e2f2d168838a9cf5ec23777b92b6b98f56be 100644 (file)
 #include "lwip/inet.h"
 #include "lwip/sockets.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* some rarely used options */
 #ifndef LWIP_DNS_API_DECLARE_H_ERRNO
 #define LWIP_DNS_API_DECLARE_H_ERRNO 1
@@ -111,6 +115,10 @@ int lwip_getaddrinfo(const char *nodename,
        lwip_getaddrinfo(nodname, servname, hints, res)
 #endif /* LWIP_COMPAT_SOCKETS */
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LWIP_DNS && LWIP_SOCKET */
 
 #endif /* __LWIP_NETDB_H__ */
index a8790b5f6a58a1b0f2b2a962ecc14802fe93b712..c14289b8e3aa02b9b2e52750e1392020401563cf 100644 (file)
@@ -39,6 +39,7 @@
 #include "lwip/err.h"
 
 #include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
 
 #include "lwip/def.h"
 #include "lwip/pbuf.h"
@@ -48,6 +49,9 @@ struct dhcp;
 #if LWIP_AUTOIP
 struct autoip;
 #endif
+#if LWIP_IPV6_DHCP6
+#include "lwip/dhcp6.h"
+#endif /* LWIP_IPV6_DHCP6 */
 
 #ifdef __cplusplus
 extern "C" {
@@ -117,6 +121,18 @@ typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
  */
 typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
        ip_addr_t *ipaddr);
+#if LWIP_IPV6
+/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet
+ * shall be sent. For ethernet netif, set this to 'nd_output' and set
+ * 'linkoutput'.
+ *
+ * @param netif The netif which shall send a packet
+ * @param p The packet to send (p->payload points to IP header)
+ * @param ipaddr The IPv6 address to which the packet shall be sent
+ */
+typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p,
+       ip6_addr_t *ipaddr);
+#endif /* LWIP_IPV6 */
 /** Function prototype for netif->linkoutput functions. Only used for ethernet
  * netifs. This function is called by ARP when a packet shall be sent.
  *
@@ -129,6 +145,11 @@ typedef void (*netif_status_callback_fn)(struct netif *netif);
 /** Function prototype for netif igmp_mac_filter functions */
 typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
        ip_addr_t *group, u8_t action);
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+/** Function prototype for netif mld_mac_filter functions */
+typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif,
+       ip6_addr_t *group, u8_t action);
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
 
 /** Generic data structure used for all lwIP network interfaces.
  *  The following fields should be filled in by the initialization
@@ -142,6 +163,13 @@ struct netif {
   ip_addr_t netmask;
   ip_addr_t gw;
 
+#if LWIP_IPV6
+  /** Array of IPv6 addresses for this netif. */
+  ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
+  /** The state of each IPv6 address (Tentative, Preferred, etc).
+   * @see ip6_addr.h */
+  u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
+#endif /* LWIP_IPV6 */
   /** This function is called by the network device driver
    *  to pass a packet up the TCP/IP stack. */
   netif_input_fn input;
@@ -153,6 +181,12 @@ struct netif {
    *  to send a packet on the interface. This function outputs
    *  the pbuf as-is on the link medium. */
   netif_linkoutput_fn linkoutput;
+#if LWIP_IPV6
+  /** This function is called by the IPv6 module when it wants
+   *  to send a packet on the interface. This function typically
+   *  first resolves the hardware address, then sends the packet. */
+  netif_output_ip6_fn output_ip6;
+#endif /* LWIP_IPV6 */
 #if LWIP_NETIF_STATUS_CALLBACK
   /** This function is called when the netif state is set to up or down
    */
@@ -174,6 +208,18 @@ struct netif {
   /** the AutoIP client state information for this netif */
   struct autoip *autoip;
 #endif
+#if LWIP_IPV6_AUTOCONFIG
+  /** is this netif enabled for IPv6 autoconfiguration */
+  u8_t ip6_autoconfig_enabled;
+#endif /* LWIP_IPV6_AUTOCONFIG */
+#if LWIP_IPV6_SEND_ROUTER_SOLICIT
+  /** Number of Router Solicitation messages that remain to be sent. */
+  u8_t rs_count;
+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
+#if LWIP_IPV6_DHCP6
+  /** the DHCPv6 client state information for this netif */
+  struct dhcp6 *dhcp6;
+#endif /* LWIP_IPV6_DHCP6 */
 #if LWIP_NETIF_HOSTNAME
   /* the hostname for this netif, NULL is a valid value */
   char*  hostname;
@@ -208,10 +254,15 @@ struct netif {
   u32_t ifoutdiscards;
 #endif /* LWIP_SNMP */
 #if LWIP_IGMP
-  /** This function could be called to add or delete a entry in the multicast
+  /** This function could be called to add or delete an entry in the multicast
       filter table of the ethernet MAC.*/
   netif_igmp_mac_filter_fn igmp_mac_filter;
 #endif /* LWIP_IGMP */
+#if LWIP_IPV6 && LWIP_IPV6_MLD
+  /** This function could be called to add or delete an entry in the IPv6 multicast
+      filter table of the ethernet MAC. */
+  netif_mld_mac_filter_fn mld_mac_filter;
+#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
 #if LWIP_NETIF_HWADDRHINT
   u8_t *addr_hint;
 #endif /* LWIP_NETIF_HWADDRHINT */
@@ -308,6 +359,20 @@ void netif_poll_all(void);
 #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
 #endif /* ENABLE_LOOPBACK */
 
+#if LWIP_IPV6
+#define netif_ip6_addr(netif, i)  (&(netif->ip6_addr[(i)]))
+#define netif_ip6_addr_state(netif, i)  (netif->ip6_addr_state[(i)])
+#define netif_ip6_addr_set_state(netif, i, state)  (netif->ip6_addr_state[(i)] = (state))
+s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr);
+void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit);
+#endif /* LWIP_IPV6 */
+
+#if LWIP_NETIF_HWADDRHINT
+#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint))
+#else /* LWIP_NETIF_HWADDRHINT */
+#define NETIF_SET_HWADDRHINT(netif, hint)
+#endif /* LWIP_NETIF_HWADDRHINT */
+
 #ifdef __cplusplus
 }
 #endif
index 6820ceb739d5c9a457c8aae95fb1836d60dd321e..8ae6ba4d58df5489a0cb411c64daa5fda4f03f53 100644 (file)
 #define NO_SYS                          0
 #endif
 
+/**
+ * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
+ * Mainly for compatibility to old versions.
+ */
+#ifndef NO_SYS_NO_TIMERS
+#define NO_SYS_NO_TIMERS                0
+#endif
+
 /**
  * MEMCPY: override this if you have a faster implementation at hand than the
  * one included in your C library
 #endif
 
 /**
- * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for
+ * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for
  * reassembly (whole packets, not fragments!)
  */
 #ifndef MEMP_NUM_REASSDATA
 #define MEMP_NUM_REASSDATA              5
 #endif
 
+/**
+ * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent
+ * (fragments, not whole packets!).
+ * This is only used with IP_FRAG_USES_STATIC_BUF==0 and
+ * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs
+ * where the packet is not yet sent when netif->output returns.
+ */
+#ifndef MEMP_NUM_FRAG_PBUF
+#define MEMP_NUM_FRAG_PBUF              15
+#endif
+
 /**
  * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
  * packets (pbufs) that are waiting for an ARP request (to resolve
 #endif
 
 /**
- * ARP_QUEUEING==1: Outgoing packets are queued during hardware address
- * resolution.
+ * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
+ * resolution. By default, only the most recent packet is queued per IP address.
+ * This is sufficient for most protocols and mainly reduces TCP connection
+ * startup time. Set this to 1 if you know your application sends more than one
+ * packet in a row to an IP address that is not in the ARP cache.
  */
 #ifndef ARP_QUEUEING
-#define ARP_QUEUEING                    1
+#define ARP_QUEUEING                    0
 #endif
 
 /**
  * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.
  * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.
  * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.
+ * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan)
+ * that returns 1 to accept a packet or 0 to drop a packet.
  */
 #ifndef ETHARP_SUPPORT_VLAN
 #define ETHARP_SUPPORT_VLAN             0
 /**
  * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP
  * fragmentation. Otherwise pbufs are allocated and reference the original
- * packet data to be fragmented.
+ * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1,
+ * new PBUF_RAM pbufs are used for fragments).
+ * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!
  */
 #ifndef IP_FRAG_USES_STATIC_BUF
-#define IP_FRAG_USES_STATIC_BUF         1
+#define IP_FRAG_USES_STATIC_BUF         0
 #endif
 
 /**
 #define IP_SOF_BROADCAST_RECV           0
 #endif
 
+/**
+ * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back
+ * out on the netif where it was received. This should only be used for
+ * wireless networks.
+ * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming
+ * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags!
+ */
+#ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF
+#define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0
+#endif
+
 /*
    ----------------------------------
    ---------- ICMP options ----------
 
 /**
  * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will
- * allow. At least one request buffer is required. 
+ * allow. At least one request buffer is required.
  * Does not have to be changed unless external MIBs answer request asynchronously
  */
 #ifndef SNMP_CONCURRENT_REQUESTS
  * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.
  */
 #ifndef TCP_SND_QUEUELEN
-#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF)/(TCP_MSS))
+#define TCP_SND_QUEUELEN                ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
 #endif
 
 /**
 #define SO_REUSE_RXTOALL                0
 #endif
 
+/**
+ * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of
+ * pending data in the network buffer. This is the way windows does it. It's
+ * the default for lwIP since it is smaller.
+ * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next
+ * pending datagram in bytes. This is the way linux does it. This code is only
+ * here for compatibility.
+ */
+#ifndef LWIP_FIONREAD_LINUXMODE
+#define LWIP_FIONREAD_LINUXMODE         0
+#endif
+
 /*
    ----------------------------------------
    ---------- Statistics options ----------
 #define SYS_STATS                       (NO_SYS == 0)
 #endif
 
+/**
+ * IP6_STATS==1: Enable IPv6 stats.
+ */
+#ifndef IP6_STATS
+#define IP6_STATS                       (LWIP_IPV6)
+#endif
+
+/**
+ * ICMP6_STATS==1: Enable ICMP for IPv6 stats.
+ */
+#ifndef ICMP6_STATS
+#define ICMP6_STATS                     (LWIP_IPV6 && LWIP_ICMP6)
+#endif
+
+/**
+ * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats.
+ */
+#ifndef IP6_FRAG_STATS
+#define IP6_FRAG_STATS                  (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS))
+#endif
+
+/**
+ * MLD6_STATS==1: Enable MLD for IPv6 stats.
+ */
+#ifndef MLD6_STATS
+#define MLD6_STATS                      (LWIP_IPV6 && LWIP_IPV6_MLD)
+#endif
+
+/**
+ * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats.
+ */
+#ifndef ND6_STATS
+#define ND6_STATS                       (LWIP_IPV6)
+#endif
+
 #else
 
 #define LINK_STATS                      0
 #define MEMP_STATS                      0
 #define SYS_STATS                       0
 #define LWIP_STATS_DISPLAY              0
+#define IP6_STATS                       0
+#define ICMP6_STATS                     0
+#define IP6_FRAG_STATS                  0
+#define MLD6_STATS                      0
+#define ND6_STATS                       0
 
 #endif /* LWIP_STATS */
 
 #define LWIP_CHECKSUM_ON_COPY           0
 #endif
 
+/*
+   ---------------------------------------
+   ---------- IPv6 options ---------------
+   ---------------------------------------
+*/
+/**
+ * LWIP_IPV6==1: Enable IPv6
+ */
+#ifndef LWIP_IPV6
+#define LWIP_IPV6                       0
+#endif
+
+/**
+ * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif.
+ */
+#ifndef LWIP_IPV6_NUM_ADDRESSES
+#define LWIP_IPV6_NUM_ADDRESSES         3
+#endif
+
+/**
+ * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs
+ */
+#ifndef LWIP_IPV6_FORWARD
+#define LWIP_IPV6_FORWARD               0
+#endif
+
+/**
+ * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC)
+ */
+#ifndef LWIP_ICMP6
+#define LWIP_ICMP6                      (LWIP_IPV6)
+#endif
+
+/**
+ * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in
+ * ICMPv6 error messages.
+ */
+#ifndef LWIP_ICMP6_DATASIZE
+#define LWIP_ICMP6_DATASIZE             8
+#endif
+
+/**
+ * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages
+ */
+#ifndef LWIP_ICMP6_HL
+#define LWIP_ICMP6_HL                   255
+#endif
+
+/**
+ * LWIP_ICMP6_CHECKSUM_CHECK==1: verify checksum on ICMPv6 packets
+ */
+#ifndef LWIP_ICMP6_CHECKSUM_CHECK
+#define LWIP_ICMP6_CHECKSUM_CHECK       1
+#endif
+
+/**
+ * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol.
+ */
+#ifndef LWIP_IPV6_MLD
+#define LWIP_IPV6_MLD                   (LWIP_IPV6)
+#endif
+
+/**
+ * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined.
+ */
+#ifndef MEMP_NUM_MLD6_GROUP
+#define MEMP_NUM_MLD6_GROUP             4
+#endif
+
+/**
+ * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big.
+ */
+#ifndef LWIP_IPV6_FRAG
+#define LWIP_IPV6_FRAG                  0
+#endif
+
+/**
+ * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented
+ */
+#ifndef LWIP_IPV6_REASS
+#define LWIP_IPV6_REASS                 (LWIP_IPV6)
+#endif
+
+/**
+ * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address
+ * is being resolved.
+ */
+#ifndef LWIP_ND6_QUEUEING
+#define LWIP_ND6_QUEUEING               (LWIP_IPV6)
+#endif
+
+/**
+ * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution.
+ */
+#ifndef MEMP_NUM_ND6_QUEUE
+#define MEMP_NUM_ND6_QUEUE              20
+#endif
+
+/**
+ * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache
+ */
+#ifndef LWIP_ND6_NUM_NEIGHBORS
+#define LWIP_ND6_NUM_NEIGHBORS          10
+#endif
+
+/**
+ * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache
+ */
+#ifndef LWIP_ND6_NUM_DESTINATIONS
+#define LWIP_ND6_NUM_DESTINATIONS       10
+#endif
+
+/**
+ * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache
+ */
+#ifndef LWIP_ND6_NUM_PREFIXES
+#define LWIP_ND6_NUM_PREFIXES           5
+#endif
+
+/**
+ * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache
+ */
+#ifndef LWIP_ND6_NUM_ROUTERS
+#define LWIP_ND6_NUM_ROUTERS            3
+#endif
+
+/**
+ * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send
+ * (neighbor solicit and router solicit)
+ */
+#ifndef LWIP_ND6_MAX_MULTICAST_SOLICIT
+#define LWIP_ND6_MAX_MULTICAST_SOLICIT  3
+#endif
+
+/**
+ * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages
+ * to send during neighbor reachability detection.
+ */
+#ifndef LWIP_ND6_MAX_UNICAST_SOLICIT
+#define LWIP_ND6_MAX_UNICAST_SOLICIT    3
+#endif
+
+/**
+ * Unused: See ND RFC (time in milliseconds).
+ */
+#ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME
+#define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000
+#endif
+
+/**
+ * Unused: See ND RFC
+ */
+#ifndef LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT
+#define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT  3
+#endif
+
+/**
+ * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds).
+ * May be updated by router advertisement messages.
+ */
+#ifndef LWIP_ND6_REACHABLE_TIME
+#define LWIP_ND6_REACHABLE_TIME         30000
+#endif
+
+/**
+ * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages
+ */
+#ifndef LWIP_ND6_RETRANS_TIMER
+#define LWIP_ND6_RETRANS_TIMER          1000
+#endif
+
+/**
+ * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation
+ * message is sent, during neighbor reachability detection.
+ */
+#ifndef LWIP_ND6_DELAY_FIRST_PROBE_TIME
+#define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000
+#endif
+
+/**
+ * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update
+ * Reachable time and retransmission timers, and netif MTU.
+ */
+#ifndef LWIP_ND6_ALLOW_RA_UPDATES
+#define LWIP_ND6_ALLOW_RA_UPDATES       1
+#endif
+
+/**
+ * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during
+ * network startup.
+ */
+#ifndef LWIP_IPV6_SEND_ROUTER_SOLICIT
+#define LWIP_IPV6_SEND_ROUTER_SOLICIT   1
+#endif
+
+/**
+ * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery
+ * with reachability hints for connected destinations. This helps avoid sending
+ * unicast neighbor solicitation messages.
+ */
+#ifndef LWIP_ND6_TCP_REACHABILITY_HINTS
+#define LWIP_ND6_TCP_REACHABILITY_HINTS 1
+#endif
+
+/**
+ * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862.
+ */
+#ifndef LWIP_IPV6_AUTOCONFIG
+#define LWIP_IPV6_AUTOCONFIG            (LWIP_IPV6)
+#endif
+
+/**
+ * LWIP_IPV6_DUP_DETECT_ATTEMPTS: Number of duplicate address detection attempts.
+ */
+#ifndef LWIP_IPV6_DUP_DETECT_ATTEMPTS
+#define LWIP_IPV6_DUP_DETECT_ATTEMPTS   1
+#endif
+
+/**
+ * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration.
+ */
+#ifndef LWIP_IPV6_DHCP6
+#define LWIP_IPV6_DHCP6                 0
+#endif
+
+/*
+   ---------------------------------------
+   ---------- Hook options ---------------
+   ---------------------------------------
+*/
+
+/* Hooks are undefined by default, define them to a function if you need them. */
+
+/**
+ * LWIP_HOOK_IP4_INPUT(pbuf, input_netif):
+ * - called from ip_input() (IPv4)
+ * - pbuf: received struct pbuf passed to ip_input()
+ * - input_netif: struct netif on which the packet has been received
+ * Return values:
+ * - 0: Hook has not consumed the packet, packet is processed as normal
+ * - != 0: Hook has consumed the packet.
+ * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook
+ * (i.e. free it when done).
+ */
+
+/**
+ * LWIP_HOOK_IP4_ROUTE(dest):
+ * - called from ip_route() (IPv4)
+ * - dest: destination IPv4 address
+ * Returns the destination netif or NULL if no destination netif is found. In
+ * that case, ip_route() continues as normal.
+ */
+
 /*
    ---------------------------------------
    ---------- Debugging options ----------
 #define DNS_DEBUG                       LWIP_DBG_OFF
 #endif
 
+/**
+ * IP6_DEBUG: Enable debugging for IPv6.
+ */
+#ifndef IP6_DEBUG
+#define IP6_DEBUG                       LWIP_DBG_OFF
+#endif
+
 #endif /* __LWIP_OPT_H__ */
index 9ab75afd9b83250ab0d35aa962e990408d54160f..41c49099ff566eaa460ef5039f43f6d146fb1ea9 100644 (file)
 extern "C" {
 #endif
 
+/** Currently, the pbuf_custom code is only needed for one specific configuration
+ * of IP_FRAG */
+#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
+
+/* @todo: We need a mechanism to prevent wasting memory in every pbuf
+   (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */
+
 #define PBUF_TRANSPORT_HLEN 20
+#if LWIP_IPV6
+#define PBUF_IP_HLEN        40
+#else
 #define PBUF_IP_HLEN        20
+#endif
 
 typedef enum {
   PBUF_TRANSPORT,
@@ -59,7 +70,16 @@ typedef enum {
 
 
 /** indicates this packet's data should be immediately passed to the application */
-#define PBUF_FLAG_PUSH 0x01U
+#define PBUF_FLAG_PUSH      0x01U
+/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
+    a pbuf differently */
+#define PBUF_FLAG_IS_CUSTOM 0x02U
+/** indicates this pbuf is UDP multicast to be looped back */
+#define PBUF_FLAG_MCASTLOOP 0x04U
+/** indicates this pbuf was received as link-level broadcast */
+#define PBUF_FLAG_LLBCAST   0x08U
+/** indicates this pbuf was received as link-level multicast */
+#define PBUF_FLAG_LLMCAST   0x10U
 
 struct pbuf {
   /** next pbuf in singly linked pbuf chain */
@@ -67,7 +87,7 @@ struct pbuf {
 
   /** pointer to the actual data in the buffer */
   void *payload;
-  
+
   /**
    * total length of this buffer and all next buffers in chain
    * belonging to the same packet.
@@ -76,9 +96,9 @@ struct pbuf {
    * p->tot_len == p->len + (p->next? p->next->tot_len: 0)
    */
   u16_t tot_len;
-  
+
   /** length of this buffer */
-  u16_t len;  
+  u16_t len;
 
   /** pbuf_type as u8_t instead of enum to save space */
   u8_t /*pbuf_type*/ type;
@@ -92,13 +112,48 @@ struct pbuf {
    * the stack itself, or pbuf->next pointers from a chain.
    */
   u16_t ref;
-  
 };
 
+#if LWIP_SUPPORT_CUSTOM_PBUF
+/** Prototype for a function to free a custom pbuf */
+typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
+
+/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
+struct pbuf_custom {
+  /** The actual pbuf */
+  struct pbuf pbuf;
+  /** This function is called when pbuf_free deallocates this pbuf(_custom) */
+  pbuf_free_custom_fn custom_free_function;
+};
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
+
+#if LWIP_TCP && TCP_QUEUE_OOSEQ
+/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
+#ifndef PBUF_POOL_FREE_OOSEQ
+#define PBUF_POOL_FREE_OOSEQ 1
+#endif /* PBUF_POOL_FREE_OOSEQ */
+#if NO_SYS && PBUF_POOL_FREE_OOSEQ
+extern volatile u8_t pbuf_free_ooseq_pending;
+void pbuf_free_ooseq();
+/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
+    at regular intervals from main level to check if ooseq pbufs need to be
+    freed! */
+#define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \
+  /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \
+     ooseq queued pbufs now */ \
+  pbuf_free_ooseq(); }}while(0)
+#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/
+#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */
+
 /* Initializes the pbuf module. This call is empty for now, but may not be in future. */
 #define pbuf_init()
 
-struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);
+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
+#if LWIP_SUPPORT_CUSTOM_PBUF
+struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
+                                 struct pbuf_custom *p, void *payload_mem,
+                                 u16_t payload_mem_len);
+#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
 void pbuf_realloc(struct pbuf *p, u16_t size); 
 u8_t pbuf_header(struct pbuf *p, s16_t header_size);
 void pbuf_ref(struct pbuf *p);
@@ -116,6 +171,11 @@ err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
                        u16_t len, u16_t *chksum);
 #endif /* LWIP_CHECKSUM_ON_COPY */
 
+u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
+u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
+u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
+u16_t pbuf_strstr(struct pbuf* p, const char* substr);
+
 #ifdef __cplusplus
 }
 #endif
index 17023d24b1e572bba998c78c5f236e6414e734f8..f0c8ed4758a99c0298b5a478f9c95eb78ca12f08 100644 (file)
@@ -40,6 +40,7 @@
 #include "lwip/def.h"
 #include "lwip/ip.h"
 #include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -48,18 +49,39 @@ extern "C" {
 struct raw_pcb;
 
 /** Function prototype for raw pcb receive callback functions.
  * @param arg user supplied argument (raw_pcb.recv_arg)
  * @param pcb the raw_pcb which received data
  * @param p the packet buffer that was received
  * @param addr the remote IP address from which the packet was received
  * @return 1 if the packet was 'eaten' (aka. deleted),
  *         0 if the packet lives on
  * If returning 1, the callback is responsible for freeing the pbuf
  * if it's not used any more.
  */
+ * @param arg user supplied argument (raw_pcb.recv_arg)
+ * @param pcb the raw_pcb which received data
+ * @param p the packet buffer that was received
+ * @param addr the remote IP address from which the packet was received
+ * @return 1 if the packet was 'eaten' (aka. deleted),
+ *         0 if the packet lives on
+ * If returning 1, the callback is responsible for freeing the pbuf
+ * if it's not used any more.
+ */
 typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
     ip_addr_t *addr);
 
+#if LWIP_IPV6
+/** Function prototype for raw pcb IPv6 receive callback functions.
+ * @param arg user supplied argument (raw_pcb.recv_arg)
+ * @param pcb the raw_pcb which received data
+ * @param p the packet buffer that was received
+ * @param addr the remote IPv6 address from which the packet was received
+ * @return 1 if the packet was 'eaten' (aka. deleted),
+ *         0 if the packet lives on
+ * If returning 1, the callback is responsible for freeing the pbuf
+ * if it's not used any more.
+ */
+typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+    ip6_addr_t *addr);
+#endif /* LWIP_IPV6 */
+
+#if LWIP_IPV6
+#define RAW_PCB_RECV_IP6  raw_recv_ip6_fn ip6;
+#else
+#define RAW_PCB_RECV_IP6
+#endif /* LWIP_IPV6 */
+
 struct raw_pcb {
   /* Common members of all PCB types */
   IP_PCB;
@@ -69,7 +91,10 @@ struct raw_pcb {
   u8_t protocol;
 
   /** receive callback function */
-  raw_recv_fn recv;
+  union {
+    raw_recv_fn ip4;
+    RAW_PCB_RECV_IP6
+  } recv;
   /* user-supplied argument for the recv callback */
   void *recv_arg;
 };
@@ -85,6 +110,14 @@ void             raw_recv       (struct raw_pcb *pcb, raw_recv_fn recv, void *re
 err_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
 err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);
 
+#if LWIP_IPV6
+struct raw_pcb * raw_new_ip6   (u8_t proto);
+#define          raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr))
+#define          raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr))
+#define          raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg)
+#define          raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr))
+#endif /* LWIP_IPV6 */
+
 /* The following functions are the lower layer interface to RAW. */
 u8_t             raw_input      (struct pbuf *p, struct netif *inp);
 #define raw_init() /* Compatibility define, not init needed. */
index b6996ca9595683d60b60c5d6a64bc181c91f4ffa..605fa3f16c9c9f3f728d3bf3804ddcb082e27159 100644 (file)
 extern "C" {
 #endif
 
-#define SNMP_ASN1_UNIV   (!0x80 | !0x40)
-#define SNMP_ASN1_APPLIC (!0x80 |  0x40)
-#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
+#define SNMP_ASN1_UNIV   (0)    /* (!0x80 | !0x40) */
+#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 |  0x40) */
+#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
 
-#define SNMP_ASN1_CONSTR (0x20)
-#define SNMP_ASN1_PRIMIT (!0x20)
+#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
+#define SNMP_ASN1_PRIMIT (0)    /* (!0x20) */
 
 /* universal tags */
 #define SNMP_ASN1_INTEG  2
index 26ff0b34420bde1e27dda723f21f44633171ab4b..fcc37b37650483ef5397dd93a5bfdddae7db4d26 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "lwip/ip_addr.h"
 #include "lwip/inet.h"
+#include "lwip/inet6.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -53,13 +54,28 @@ struct sockaddr_in {
   u8_t sin_family;
   u16_t sin_port;
   struct in_addr sin_addr;
-  char sin_zero[8];
+#define SIN_ZERO_LEN 8
+  char sin_zero[SIN_ZERO_LEN];
 };
 
+#if LWIP_IPV6
+struct sockaddr_in6 {
+  u8_t sin6_len;             /* length of this structure */
+  u8_t sin6_family;          /* AF_INET6                 */
+  u16_t sin6_port;           /* Transport layer port #   */
+  u32_t sin6_flowinfo;       /* IPv6 flow information    */
+  struct in6_addr sin6_addr; /* IPv6 address             */
+};
+#endif /* LWIP_IPV6 */
+
 struct sockaddr {
   u8_t sa_len;
   u8_t sa_family;
-  u16_t sa_data[14];
+#if LWIP_IPV6
+  u8_t sa_data[22];
+#else /* LWIP_IPV6 */
+  u8_t sa_data[14];
+#endif /* LWIP_IPV6 */
 };
 
 #ifndef socklen_t
@@ -118,7 +134,13 @@ struct linger {
 
 #define AF_UNSPEC       0
 #define AF_INET         2
+#if LWIP_IPV6
+#define AF_INET6        10
+#else /* LWIP_IPV6 */
+#define AF_INET6        AF_UNSPEC
+#endif /* LWIP_IPV6 */
 #define PF_INET         AF_INET
+#define PF_INET6        AF_INET6
 #define PF_UNSPEC       AF_UNSPEC
 
 #define IPPROTO_IP      0
@@ -279,6 +301,12 @@ typedef struct ip_mreq {
 #define O_NDELAY    1 /* same as O_NONBLOCK, for compatibility */
 #endif
 
+#ifndef SHUT_RD
+  #define SHUT_RD   0
+  #define SHUT_WR   1
+  #define SHUT_RDWR 2
+#endif
+
 /* FD_SET used for lwip_select */
 #ifndef FD_SET
   #undef  FD_SETSIZE
index 015b7ce79d8e5ecec0ca05393f8542c482485aa6..d911216087aca8475b8e4c392da7e31468851082 100644 (file)
@@ -144,6 +144,21 @@ struct stats_ {
 #if SYS_STATS
   struct stats_sys sys;
 #endif
+#if IP6_STATS
+  struct stats_proto ip6;
+#endif
+#if ICMP6_STATS
+  struct stats_proto icmp6;
+#endif
+#if IP6_FRAG_STATS
+  struct stats_proto ip6_frag;
+#endif
+#if MLD6_STATS
+  struct stats_igmp mld6;
+#endif
+#if ND6_STATS
+  struct stats_proto nd6;
+#endif
 };
 
 extern struct stats_ lwip_stats;
@@ -190,7 +205,7 @@ void stats_init(void);
 
 #if IGMP_STATS
 #define IGMP_STATS_INC(x) STATS_INC(x)
-#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)
+#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP")
 #else
 #define IGMP_STATS_INC(x)
 #define IGMP_STATS_DISPLAY()
@@ -268,18 +283,58 @@ void stats_init(void);
 #define SYS_STATS_DISPLAY()
 #endif
 
+#if IP6_STATS
+#define IP6_STATS_INC(x) STATS_INC(x)
+#define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6")
+#else
+#define IP6_STATS_INC(x)
+#define IP6_STATS_DISPLAY()
+#endif
+
+#if ICMP6_STATS
+#define ICMP6_STATS_INC(x) STATS_INC(x)
+#define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6")
+#else
+#define ICMP6_STATS_INC(x)
+#define ICMP6_STATS_DISPLAY()
+#endif
+
+#if IP6_FRAG_STATS
+#define IP6_FRAG_STATS_INC(x) STATS_INC(x)
+#define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG")
+#else
+#define IP6_FRAG_STATS_INC(x)
+#define IP6_FRAG_STATS_DISPLAY()
+#endif
+
+#if MLD6_STATS
+#define MLD6_STATS_INC(x) STATS_INC(x)
+#define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1")
+#else
+#define MLD6_STATS_INC(x)
+#define MLD6_STATS_DISPLAY()
+#endif
+
+#if ND6_STATS
+#define ND6_STATS_INC(x) STATS_INC(x)
+#define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND")
+#else
+#define ND6_STATS_INC(x)
+#define ND6_STATS_DISPLAY()
+#endif
+
 /* Display of statistics */
 #if LWIP_STATS_DISPLAY
 void stats_display(void);
-void stats_display_proto(struct stats_proto *proto, char *name);
-void stats_display_igmp(struct stats_igmp *igmp);
-void stats_display_mem(struct stats_mem *mem, char *name);
+void stats_display_proto(struct stats_proto *proto, const char *name);
+void stats_display_igmp(struct stats_igmp *igmp, const char *name);
+void stats_display_mem(struct stats_mem *mem, const char *name);
 void stats_display_memp(struct stats_mem *mem, int index);
 void stats_display_sys(struct stats_sys *sys);
 #else /* LWIP_STATS_DISPLAY */
 #define stats_display()
 #define stats_display_proto(proto, name)
-#define stats_display_igmp(igmp)
+#define stats_display_igmp(igmp, name)
 #define stats_display_mem(mem, name)
 #define stats_display_memp(mem, index)
 #define stats_display_sys(sys)
index f4a4f838fcfe07556d7cba0993462f76b768bd17..8a7f418bbb61d50664606ca6b935b772346fec37 100644 (file)
 
 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
 
-#include "lwip/sys.h"
 #include "lwip/mem.h"
 #include "lwip/pbuf.h"
 #include "lwip/ip.h"
 #include "lwip/icmp.h"
 #include "lwip/err.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -156,11 +157,11 @@ enum tcp_state {
  */
 #define TCP_PCB_COMMON(type) \
   type *next; /* for the linked list */ \
-  enum tcp_state state; /* TCP state */ \
-  u8_t prio; \
   void *callback_arg; \
   /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \
   DEF_ACCEPT_CALLBACK \
+  enum tcp_state state; /* TCP state */ \
+  u8_t prio; \
   /* ports are in host byte order */ \
   u16_t local_port
 
@@ -187,21 +188,22 @@ struct tcp_pcb {
 
   /* the rest of the fields are in host byte order
      as we have to do some math with them */
+
+  /* Timers */
+  u8_t polltmr, pollinterval;
+  u32_t tmr;
+
   /* receiver variables */
   u32_t rcv_nxt;   /* next seqno expected */
   u16_t rcv_wnd;   /* receiver window available */
   u16_t rcv_ann_wnd; /* receiver window to announce */
   u32_t rcv_ann_right_edge; /* announced right edge of window */
 
-  /* Timers */
-  u32_t tmr;
-  u8_t polltmr, pollinterval;
-  
   /* Retransmission timer. */
   s16_t rtime;
-  
+
   u16_t mss;   /* maximum segment size */
-  
+
   /* RTT (round trip time) estimation variables */
   u32_t rttest; /* RTT estimate in 500ms ticks */
   u32_t rtseq;  /* sequence number being timed */
@@ -211,31 +213,31 @@ struct tcp_pcb {
   u8_t nrtx;    /* number of retransmissions */
 
   /* fast retransmit/recovery */
-  u32_t lastack; /* Highest acknowledged seqno. */
   u8_t dupacks;
-  
+  u32_t lastack; /* Highest acknowledged seqno. */
+
   /* congestion avoidance/control variables */
-  u16_t cwnd;  
+  u16_t cwnd;
   u16_t ssthresh;
 
   /* sender variables */
   u32_t snd_nxt;   /* next new seqno to be sent */
-  u16_t snd_wnd;   /* sender window */
   u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
                              window update. */
   u32_t snd_lbb;       /* Sequence number of next byte to be buffered. */
+  u16_t snd_wnd;   /* sender window */
 
   u16_t acked;
-  
+
   u16_t snd_buf;   /* Available buffer space for sending (in bytes). */
-#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)
+#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
   u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */
-  
+
 #if TCP_OVERSIZE
   /* Extra bytes available at the end of the last pbuf in unsent. */
   u16_t unsent_oversize;
 #endif /* TCP_OVERSIZE */ 
-  
+
   /* These are ordered by sequence number: */
   struct tcp_seg *unsent;   /* Unsent (queued) segments. */
   struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */
@@ -279,7 +281,7 @@ struct tcp_pcb {
   u8_t keep_cnt_sent;
 };
 
-struct tcp_pcb_listen {  
+struct tcp_pcb_listen {
 /* Common members of all PCB types */
   IP_PCB;
 /* Protocol specific PCB members */
@@ -289,6 +291,9 @@ struct tcp_pcb_listen {
   u8_t backlog;
   u8_t accepts_pending;
 #endif /* TCP_LISTEN_BACKLOG */
+#if LWIP_IPV6
+  u8_t accept_any_ip_version;
+#endif /* LWIP_IPV6 */
 };
 
 #if LWIP_EVENT_API
@@ -367,6 +372,19 @@ err_t            tcp_output  (struct tcp_pcb *pcb);
 
 const char* tcp_debug_state_str(enum tcp_state s);
 
+#if LWIP_IPV6
+struct tcp_pcb * tcp_new_ip6 (void);
+#define          tcp_bind_ip6(pcb, ip6addr, port) \
+                   tcp_bind(pcb, ip6_2_ip(ip6addr), port)
+#define          tcp_connect_ip6(pcb, ip6addr, port, connected) \
+                   tcp_connect(pcb, ip6_2_ip(ip6addr), port, connected)
+struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
+#define          tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)
+#else /* LWIP_IPV6 */
+#define          tcp_listen_dual_with_backlog(pcb, backlog) tcp_listen_with_backlog(pcb, backlog)
+#define          tcp_listen_dual(pcb) tcp_listen(pcb)
+#endif /* LWIP_IPV6 */
+
 
 #ifdef __cplusplus
 }
index 320b88ef2a7a05deb40fc53cb266d5bd82bf4a69..14c92fbb4c8a3d9572f03538837664916f5e1251 100644 (file)
 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
 
 #include "lwip/tcp.h"
-#include "lwip/sys.h"
 #include "lwip/mem.h"
 #include "lwip/pbuf.h"
 #include "lwip/ip.h"
 #include "lwip/icmp.h"
 #include "lwip/err.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -278,7 +279,6 @@ PACK_STRUCT_END
 struct tcp_seg {
   struct tcp_seg *next;    /* used when putting segements on a queue */
   struct pbuf *p;          /* buffer containing data + TCP header */
-  void *dataptr;           /* pointer to the TCP data in the pbuf */
   u16_t len;               /* the TCP length of this segment */
 #if TCP_OVERSIZE_DBGCHECK
   u16_t oversize_left;     /* Extra bytes available at the end of the last
@@ -427,9 +427,20 @@ err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags);
 
 void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
 
-void tcp_rst(u32_t seqno, u32_t ackno,
-       ip_addr_t *local_ip, ip_addr_t *remote_ip,
-       u16_t local_port, u16_t remote_port);
+void tcp_rst_impl(u32_t seqno, u32_t ackno,
+       ipX_addr_t *local_ip, ipX_addr_t *remote_ip,
+       u16_t local_port, u16_t remote_port
+#if LWIP_IPV6
+       , u8_t isipv6
+#endif /* LWIP_IPV6 */
+       );
+#if LWIP_IPV6
+#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \
+  tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6)
+#else /* LWIP_IPV6 */
+#define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \
+  tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port)
+#endif /* LWIP_IPV6 */
 
 u32_t tcp_next_iss(void);
 
@@ -437,7 +448,16 @@ void tcp_keepalive(struct tcp_pcb *pcb);
 void tcp_zero_window_probe(struct tcp_pcb *pcb);
 
 #if TCP_CALCULATE_EFF_SEND_MSS
-u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr);
+u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest
+#if LWIP_IPV6
+                           , ipX_addr_t *src, u8_t isipv6
+#endif /* LWIP_IPV6 */
+                           );
+#if LWIP_IPV6
+#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest, src, isipv6)
+#else /* LWIP_IPV6 */
+#define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest)
+#endif /* LWIP_IPV6 */
 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
 
 #if LWIP_CALLBACK_API
index 995ba8ad00756d4161c6de94ba8ee8ea9f7c7256..637476e1a90cf4e095cd1514daa21154cedf07fb 100644 (file)
@@ -77,6 +77,9 @@ typedef void (*tcpip_init_done_fn)(void *arg);
 /** Function prototype for functions passed to tcpip_callback() */
 typedef void (*tcpip_callback_fn)(void *ctx);
 
+/* Forward declarations */
+struct tcpip_callback_msg;
+
 void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
 
 #if LWIP_NETCONN
@@ -98,6 +101,10 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
 err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
 #define tcpip_callback(f, ctx)              tcpip_callback_with_block(f, ctx, 1)
 
+struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx);
+void   tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg);
+err_t  tcpip_trycallback(struct tcpip_callback_msg* msg);
+
 /* free pbufs or heap memory from another context without blocking */
 err_t pbuf_free_callback(struct pbuf *p);
 err_t mem_free_callback(void *m);
@@ -119,7 +126,8 @@ enum tcpip_msg_type {
   TCPIP_MSG_TIMEOUT,
   TCPIP_MSG_UNTIMEOUT,
 #endif /* LWIP_TCPIP_TIMEOUT */
-  TCPIP_MSG_CALLBACK
+  TCPIP_MSG_CALLBACK,
+  TCPIP_MSG_CALLBACK_STATIC
 };
 
 struct tcpip_msg {
index c680b24c2cb68d81e066a41f2b206d233234476e..04e78e0feab10c30512c7eb39f4d9f87f093edf9 100644 (file)
 
 #include "lwip/opt.h"
 
+/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
+#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
+
+#if LWIP_TIMERS
+
 #include "lwip/err.h"
+#if !NO_SYS
 #include "lwip/sys.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -70,13 +77,13 @@ struct sys_timeo {
 void sys_timeouts_init(void);
 
 #if LWIP_DEBUG_TIMERNAMES
-void sys_timeout_debug(u32_t msecs, sys_timeout_handler h, void *arg, const char* handler_name);
+void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name);
 #define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler)
 #else /* LWIP_DEBUG_TIMERNAMES */
-void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
+void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
 #endif /* LWIP_DEBUG_TIMERNAMES */
 
-void sys_untimeout(sys_timeout_handler h, void *arg);
+void sys_untimeout(sys_timeout_handler handler, void *arg);
 #if NO_SYS
 void sys_check_timeouts(void);
 void sys_restart_timeouts(void);
@@ -89,4 +96,5 @@ void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
 }
 #endif
 
+#endif /* LWIP_TIMERS */
 #endif /* __LWIP_TIMERS_H__ */
index 80d29b62ebda45670cfa9d74f51d9e0f53cd90ea..648c9a469b2f6bbe66dd8145443a2ee7266c357e 100644 (file)
@@ -40,6 +40,7 @@
 #include "lwip/netif.h"
 #include "lwip/ip_addr.h"
 #include "lwip/ip.h"
+#include "lwip/ip6_addr.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -63,9 +64,10 @@ PACK_STRUCT_END
 #  include "arch/epstruct.h"
 #endif
 
-#define UDP_FLAGS_NOCHKSUM 0x01U
-#define UDP_FLAGS_UDPLITE  0x02U
-#define UDP_FLAGS_CONNECTED  0x04U
+#define UDP_FLAGS_NOCHKSUM       0x01U
+#define UDP_FLAGS_UDPLITE        0x02U
+#define UDP_FLAGS_CONNECTED      0x04U
+#define UDP_FLAGS_MULTICAST_LOOP 0x08U
 
 struct udp_pcb;
 
@@ -86,6 +88,26 @@ struct udp_pcb;
 typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
     ip_addr_t *addr, u16_t port);
 
+#if LWIP_IPV6
+/** Function prototype for udp pcb IPv6 receive callback functions
+ * The callback is responsible for freeing the pbuf
+ * if it's not used any more.
+ *
+ * @param arg user supplied argument (udp_pcb.recv_arg)
+ * @param pcb the udp_pcb which received data
+ * @param p the packet buffer that was received
+ * @param addr the remote IPv6 address from which the packet was received
+ * @param port the remote port from which the packet was received
+ */
+typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+    ip6_addr_t *addr, u16_t port);
+#endif /* LWIP_IPV6 */
+
+#if LWIP_IPV6
+#define UDP_PCB_RECV_IP6  udp_recv_ip6_fn ip6;
+#else
+#define UDP_PCB_RECV_IP6
+#endif /* LWIP_IPV6 */
 
 struct udp_pcb {
 /* Common members of all PCB types */
@@ -110,7 +132,10 @@ struct udp_pcb {
 #endif /* LWIP_UDPLITE */
 
   /** receive callback function */
-  udp_recv_fn recv;
+  union {
+    udp_recv_fn ip4;
+    UDP_PCB_RECV_IP6
+  }recv;
   /** user-supplied argument for the recv callback */
   void *recv_arg;  
 };
@@ -122,12 +147,12 @@ extern struct udp_pcb *udp_pcbs;
 struct udp_pcb * udp_new        (void);
 void             udp_remove     (struct udp_pcb *pcb);
 err_t            udp_bind       (struct udp_pcb *pcb, ip_addr_t *ipaddr,
-                 u16_t port);
+                                 u16_t port);
 err_t            udp_connect    (struct udp_pcb *pcb, ip_addr_t *ipaddr,
-                 u16_t port);
-void             udp_disconnect    (struct udp_pcb *pcb);
+                                 u16_t port);
+void             udp_disconnect (struct udp_pcb *pcb);
 void             udp_recv       (struct udp_pcb *pcb, udp_recv_fn recv,
-         void *recv_arg);
+                                 void *recv_arg);
 err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p,
                                  ip_addr_t *dst_ip, u16_t dst_port,
                                  struct netif *netif);
@@ -147,7 +172,7 @@ err_t            udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
                                  u8_t have_chksum, u16_t chksum);
 #endif /* LWIP_CHECKSUM_ON_COPY */
 
-#define          udp_flags(pcb)  ((pcb)->flags)
+#define          udp_flags(pcb) ((pcb)->flags)
 #define          udp_setflags(pcb, f)  ((pcb)->flags = (f))
 
 /* The following functions are the lower layer interface to UDP. */
@@ -155,6 +180,26 @@ void             udp_input      (struct pbuf *p, struct netif *inp);
 
 #define udp_init() /* Compatibility define, not init needed. */
 
+#if LWIP_IPV6
+struct udp_pcb * udp_new_ip6(void);
+#define          udp_bind_ip6(pcb, ip6addr, port) \
+                   udp_bind(pcb, ip6_2_ip(ip6addr), port)
+#define          udp_connect_ip6(pcb, ip6addr, port) \
+                   udp_connect(pcb, ip6_2_ip(ip6addr), port)
+#define          udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \
+                   udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg)
+#define          udp_sendto_ip6(pcb, pbuf, ip6addr, port) \
+                   udp_sendto(pcb, pbuf, ip6_2_ip(ip6addr), port)
+#define          udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \
+                   udp_sendto_if(pcb, pbuf, ip6_2_ip(ip6addr), port, netif)
+#if LWIP_CHECKSUM_ON_COPY
+#define          udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \
+                   udp_sendto_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, have_chk, chksum)
+#define          udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \
+                   udp_sendto_if_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, netif, have_chk, chksum)
+#endif /*LWIP_CHECKSUM_ON_COPY */
+#endif /* LWIP_IPV6 */
+
 #if UDP_DEBUG
 void udp_debug_print(struct udp_hdr *udphdr);
 #else
index a4803ec4dbbd9341b05f049cbf056f1058a6408e..2eda1488b17515ff8861acae46772a1b71f8beb5 100644 (file)
@@ -94,8 +94,8 @@ PACK_STRUCT_BEGIN
  * if 'type' in ethernet header is ETHTYPE_VLAN.
  * See IEEE802.Q */
 struct eth_vlan_hdr {
-  PACK_STRUCT_FIELD(u16_t tpid);
   PACK_STRUCT_FIELD(u16_t prio_vid);
+  PACK_STRUCT_FIELD(u16_t tpid);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
 #ifdef PACK_STRUCT_USE_INCLUDES
@@ -134,11 +134,12 @@ PACK_STRUCT_END
 /** 5 seconds period */
 #define ARP_TMR_INTERVAL 5000
 
-#define ETHTYPE_ARP       0x0806
-#define ETHTYPE_IP        0x0800
-#define ETHTYPE_VLAN      0x8100
-#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */
-#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */
+#define ETHTYPE_ARP       0x0806U
+#define ETHTYPE_IP        0x0800U
+#define ETHTYPE_VLAN      0x8100U
+#define ETHTYPE_IPV6      0x86DDU
+#define ETHTYPE_PPPOEDISC 0x8863U  /* PPP Over Ethernet Discovery Stage */
+#define ETHTYPE_PPPOE     0x8864U  /* PPP Over Ethernet Session Stage */
 
 /** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables
  * or known to be 32-bit aligned within the protocol header. */
index fad7ec3d469bdb7d9d856087bc83b0b17a331d61..e1cdfa51991f67b8ff1be7c425a4334a6cb79c9f 100644 (file)
 #endif
 PACK_STRUCT_BEGIN
 struct pppoehdr {
-       PACK_STRUCT_FIELD(u8_t vertype);
-       PACK_STRUCT_FIELD(u8_t code);
-       PACK_STRUCT_FIELD(u16_t session);
-       PACK_STRUCT_FIELD(u16_t plen);
+  PACK_STRUCT_FIELD(u8_t vertype);
+  PACK_STRUCT_FIELD(u8_t code);
+  PACK_STRUCT_FIELD(u16_t session);
+  PACK_STRUCT_FIELD(u16_t plen);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
 #ifdef PACK_STRUCT_USE_INCLUDES
@@ -96,8 +96,8 @@ PACK_STRUCT_END
 #endif
 PACK_STRUCT_BEGIN
 struct pppoetag {
-       PACK_STRUCT_FIELD(u16_t tag);
-       PACK_STRUCT_FIELD(u16_t len);
+  PACK_STRUCT_FIELD(u16_t tag);
+  PACK_STRUCT_FIELD(u16_t len);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
 #ifdef PACK_STRUCT_USE_INCLUDES
@@ -105,40 +105,40 @@ PACK_STRUCT_END
 #endif
 
 
-#define PPPOE_STATE_INITIAL    0
-#define PPPOE_STATE_PADI_SENT  1
-#define        PPPOE_STATE_PADR_SENT   2
-#define        PPPOE_STATE_SESSION     3
-#define        PPPOE_STATE_CLOSING     4
+#define PPPOE_STATE_INITIAL   0
+#define PPPOE_STATE_PADI_SENT 1
+#define PPPOE_STATE_PADR_SENT 2
+#define PPPOE_STATE_SESSION   3
+#define PPPOE_STATE_CLOSING   4
 /* passive */
-#define        PPPOE_STATE_PADO_SENT   1
-
-#define PPPOE_HEADERLEN        sizeof(struct pppoehdr)
-#define        PPPOE_VERTYPE   0x11    /* VER=1, TYPE = 1 */
-
-#define        PPPOE_TAG_EOL           0x0000          /* end of list */
-#define        PPPOE_TAG_SNAME         0x0101          /* service name */
-#define        PPPOE_TAG_ACNAME        0x0102          /* access concentrator name */
-#define        PPPOE_TAG_HUNIQUE       0x0103          /* host unique */
-#define        PPPOE_TAG_ACCOOKIE      0x0104          /* AC cookie */
-#define        PPPOE_TAG_VENDOR        0x0105          /* vendor specific */
-#define        PPPOE_TAG_RELAYSID      0x0110          /* relay session id */
-#define        PPPOE_TAG_SNAME_ERR     0x0201          /* service name error */
-#define        PPPOE_TAG_ACSYS_ERR     0x0202          /* AC system error */
-#define        PPPOE_TAG_GENERIC_ERR   0x0203          /* gerneric error */
-
-#define PPPOE_CODE_PADI                0x09            /* Active Discovery Initiation */
-#define        PPPOE_CODE_PADO         0x07            /* Active Discovery Offer */
-#define        PPPOE_CODE_PADR         0x19            /* Active Discovery Request */
-#define        PPPOE_CODE_PADS         0x65            /* Active Discovery Session confirmation */
-#define        PPPOE_CODE_PADT         0xA7            /* Active Discovery Terminate */
+#define PPPOE_STATE_PADO_SENT 1
+
+#define PPPOE_HEADERLEN       sizeof(struct pppoehdr)
+#define PPPOE_VERTYPE         0x11    /* VER=1, TYPE = 1 */
+
+#define PPPOE_TAG_EOL         0x0000  /* end of list */
+#define PPPOE_TAG_SNAME       0x0101  /* service name */
+#define PPPOE_TAG_ACNAME      0x0102  /* access concentrator name */
+#define PPPOE_TAG_HUNIQUE     0x0103  /* host unique */
+#define PPPOE_TAG_ACCOOKIE    0x0104  /* AC cookie */
+#define PPPOE_TAG_VENDOR      0x0105  /* vendor specific */
+#define PPPOE_TAG_RELAYSID    0x0110  /* relay session id */
+#define PPPOE_TAG_SNAME_ERR   0x0201  /* service name error */
+#define PPPOE_TAG_ACSYS_ERR   0x0202  /* AC system error */
+#define PPPOE_TAG_GENERIC_ERR 0x0203  /* gerneric error */
+
+#define PPPOE_CODE_PADI       0x09    /* Active Discovery Initiation */
+#define PPPOE_CODE_PADO       0x07    /* Active Discovery Offer */
+#define PPPOE_CODE_PADR       0x19    /* Active Discovery Request */
+#define PPPOE_CODE_PADS       0x65    /* Active Discovery Session confirmation */
+#define PPPOE_CODE_PADT       0xA7    /* Active Discovery Terminate */
 
 #ifndef ETHERMTU
 #define ETHERMTU 1500
 #endif
 
 /* two byte PPP protocol discriminator, then IP data */
-#define        PPPOE_MAXMTU    (ETHERMTU-PPPOE_HEADERLEN-2)
+#define PPPOE_MAXMTU          (ETHERMTU-PPPOE_HEADERLEN-2)
 
 #ifndef PPPOE_MAX_AC_COOKIE_LEN
 #define PPPOE_MAX_AC_COOKIE_LEN   64
index 6631b40ad89e0104bc9ea079c9700121f5355962..8b333dd90e7a07ae0f3f4cc4421b340613f76d6f 100644 (file)
@@ -55,6 +55,7 @@
 #include "lwip/dhcp.h"
 #include "lwip/autoip.h"
 #include "netif/etharp.h"
+#include "lwip/ip6.h"
 
 #if PPPOE_SUPPORT
 #include "netif/ppp_oe.h"
 const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
 const struct eth_addr ethzero = {{0,0,0,0,0,0}};
 
+/** The 24-bit IANA multicast OUI is 01-00-5e: */
+#define LL_MULTICAST_ADDR_0 0x01
+#define LL_MULTICAST_ADDR_1 0x00
+#define LL_MULTICAST_ADDR_2 0x5e
+
 #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
 
 /** the time an ARP entry stays valid after its last update,
  *  for ARP_TMR_INTERVAL = 5000, this is
  *  (240 * 5) seconds = 20 minutes.
  */
-#define ARP_MAXAGE 240
+#define ARP_MAXAGE              240
+/** Re-request a used ARP entry 1 minute before it would expire to prevent
+ *  breaking a steadily used connection because the ARP entry timed out. */
+#define ARP_AGE_REREQUEST_USED  (ARP_MAXAGE - 12)
+
 /** the time an ARP entry stays pending after first request,
  *  for ARP_TMR_INTERVAL = 5000, this is
  *  (2 * 5) seconds = 10 seconds.
@@ -86,24 +96,28 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}};
 enum etharp_state {
   ETHARP_STATE_EMPTY = 0,
   ETHARP_STATE_PENDING,
-  ETHARP_STATE_STABLE
+  ETHARP_STATE_STABLE,
+  ETHARP_STATE_STABLE_REREQUESTING
+#if ETHARP_SUPPORT_STATIC_ENTRIES
+  ,ETHARP_STATE_STATIC
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
 };
 
 struct etharp_entry {
 #if ARP_QUEUEING
   /** Pointer to queue of pending outgoing packets on this ARP entry. */
   struct etharp_q_entry *q;
+#else /* ARP_QUEUEING */
+  /** Pointer to a single pending outgoing packet on this ARP entry. */
+  struct pbuf *q;
 #endif /* ARP_QUEUEING */
   ip_addr_t ipaddr;
-  struct eth_addr ethaddr;
 #if LWIP_SNMP
   struct netif *netif;
 #endif /* LWIP_SNMP */
+  struct eth_addr ethaddr;
   u8_t state;
   u8_t ctime;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
-  u8_t static_entry;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
 };
 
 static struct etharp_entry arp_table[ARP_TABLE_SIZE];
@@ -116,7 +130,9 @@ static u8_t etharp_cached_entry;
     the cache (even if this means removing an active entry or so). */
 #define ETHARP_FLAG_TRY_HARD     1
 #define ETHARP_FLAG_FIND_ONLY    2
+#if ETHARP_SUPPORT_STATIC_ENTRIES
 #define ETHARP_FLAG_STATIC_ENTRY 4
+#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
 
 #if LWIP_NETIF_HWADDRHINT
 #define ETHARP_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \
@@ -125,8 +141,6 @@ static u8_t etharp_cached_entry;
 #define ETHARP_SET_HINT(netif, hint)  (etharp_cached_entry = (hint))
 #endif /* LWIP_NETIF_HWADDRHINT */
 
-static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
-
 
 /* Some checks, instead of etharp_init(): */
 #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
@@ -154,28 +168,28 @@ free_etharp_q(struct etharp_q_entry *q)
     memp_free(MEMP_ARP_QUEUE, r);
   }
 }
+#else /* ARP_QUEUEING */
+
+/** Compatibility define: free the queued pbuf */
+#define free_etharp_q(q) pbuf_free(q)
+
 #endif /* ARP_QUEUEING */
 
 /** Clean up ARP table entries */
 static void
-free_entry(int i)
+etharp_free_entry(int i)
 {
   /* remove from SNMP ARP index tree */
   snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
-#if ARP_QUEUEING
   /* and empty packet queue */
   if (arp_table[i].q != NULL) {
     /* remove all queued packets */
-    LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
+    LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
     free_etharp_q(arp_table[i].q);
     arp_table[i].q = NULL;
   }
-#endif /* ARP_QUEUEING */
-  /* recycle entry for re-use */      
+  /* recycle entry for re-use */
   arp_table[i].state = ETHARP_STATE_EMPTY;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
-  arp_table[i].static_entry = 0;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
 #ifdef LWIP_DEBUG
   /* for debugging, clean out the complete entry */
   arp_table[i].ctime = 0;
@@ -204,24 +218,29 @@ etharp_tmr(void)
     u8_t state = arp_table[i].state;
     if (state != ETHARP_STATE_EMPTY
 #if ETHARP_SUPPORT_STATIC_ENTRIES
-      && (arp_table[i].static_entry == 0)
+      && (state != ETHARP_STATE_STATIC)
 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
       ) {
-    arp_table[i].ctime++;
+      arp_table[i].ctime++;
       if ((arp_table[i].ctime >= ARP_MAXAGE) ||
-        ((arp_table[i].state == ETHARP_STATE_PENDING)  &&
-         (arp_table[i].ctime >= ARP_MAXPENDING))) {
-         /* pending or stable entry has become old! */
-      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
-           arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
-      /* clean up entries that have just been expired */
-        free_entry(i);
-    }
+          ((arp_table[i].state == ETHARP_STATE_PENDING)  &&
+           (arp_table[i].ctime >= ARP_MAXPENDING))) {
+        /* pending or stable entry has become old! */
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
+             arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
+        /* clean up entries that have just been expired */
+        etharp_free_entry(i);
+      }
+      else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {
+        /* Reset state to stable, so that the next transmitted packet will
+           re-send an ARP request. */
+        arp_table[i].state = ETHARP_STATE_STABLE;
+      }
 #if ARP_QUEUEING
-    /* still pending entry? (not expired) */
-    if (arp_table[i].state == ETHARP_STATE_PENDING) {
+      /* still pending entry? (not expired) */
+      if (arp_table[i].state == ETHARP_STATE_PENDING) {
         /* resend an ARP query here? */
-    }
+      }
 #endif /* ARP_QUEUEING */
     }
   }
@@ -249,17 +268,15 @@ etharp_tmr(void)
  * entry is found or could be recycled.
  */
 static s8_t
-find_entry(ip_addr_t *ipaddr, u8_t flags)
+etharp_find_entry(ip_addr_t *ipaddr, u8_t flags)
 {
   s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
   s8_t empty = ARP_TABLE_SIZE;
   u8_t i = 0, age_pending = 0, age_stable = 0;
-#if ARP_QUEUEING
   /* oldest entry with packets on queue */
   s8_t old_queue = ARP_TABLE_SIZE;
   /* its age */
   u8_t age_queue = 0;
-#endif /* ARP_QUEUEING */
 
   /**
    * a) do a search through the cache, remember candidates
@@ -280,51 +297,49 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
     u8_t state = arp_table[i].state;
     /* no empty entry found yet and now we do find one? */
     if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
-      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i));
       /* remember first empty entry */
       empty = i;
     } else if (state != ETHARP_STATE_EMPTY) {
-      LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
-        state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
+      LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
+        state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
       /* if given, does IP address match IP address in ARP entry? */
       if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
-        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i));
         /* found exact IP address match, simply bail out */
         return i;
       }
       /* pending entry? */
       if (state == ETHARP_STATE_PENDING) {
-      /* pending with queued packets? */
-#if ARP_QUEUEING
+        /* pending with queued packets? */
         if (arp_table[i].q != NULL) {
-        if (arp_table[i].ctime >= age_queue) {
-          old_queue = i;
-          age_queue = arp_table[i].ctime;
-        }
+          if (arp_table[i].ctime >= age_queue) {
+            old_queue = i;
+            age_queue = arp_table[i].ctime;
+          }
         } else
-#endif /* ARP_QUEUEING */
-      /* pending without queued packets? */
+        /* pending without queued packets? */
         {
-        if (arp_table[i].ctime >= age_pending) {
-          old_pending = i;
-          age_pending = arp_table[i].ctime;
+          if (arp_table[i].ctime >= age_pending) {
+            old_pending = i;
+            age_pending = arp_table[i].ctime;
+          }
         }
-      }        
-    /* stable entry? */
-      } else if (state == ETHARP_STATE_STABLE) {
+      /* stable entry? */
+      } else if (state >= ETHARP_STATE_STABLE) {
 #if ETHARP_SUPPORT_STATIC_ENTRIES
         /* don't record old_stable for static entries since they never expire */
-        if (arp_table[i].static_entry == 0)
+        if (state < ETHARP_STATE_STATIC)
 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
         {
-      /* remember entry with oldest stable entry in oldest, its age in maxtime */
+          /* remember entry with oldest stable entry in oldest, its age in maxtime */
           if (arp_table[i].ctime >= age_stable) {
-        old_stable = i;
-        age_stable = arp_table[i].ctime;
+            old_stable = i;
+            age_stable = arp_table[i].ctime;
+          }
+        }
       }
     }
-  }
-    }
   }
   /* { we have no match } => try to create a new entry */
    
@@ -332,7 +347,7 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
   if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
       /* or no empty entry found and not allowed to recycle? */
       ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n"));
     return (s8_t)ERR_MEM;
   }
   
@@ -348,38 +363,34 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
   /* 1) empty entry available? */
   if (empty < ARP_TABLE_SIZE) {
     i = empty;
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
   } else {
-  /* 2) found recyclable stable entry? */
+    /* 2) found recyclable stable entry? */
     if (old_stable < ARP_TABLE_SIZE) {
-    /* recycle oldest stable*/
-    i = old_stable;
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
-#if ARP_QUEUEING
-    /* no queued packets should exist on stable entries */
-    LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
-#endif /* ARP_QUEUEING */
-  /* 3) found recyclable pending entry without queued packets? */
-  } else if (old_pending < ARP_TABLE_SIZE) {
-    /* recycle oldest pending */
-    i = old_pending;
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
-#if ARP_QUEUEING
-  /* 4) found recyclable pending entry with queued packets? */
-  } else if (old_queue < ARP_TABLE_SIZE) {
-      /* recycle oldest pending (queued packets are free in free_entry) */
-    i = old_queue;
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
-#endif /* ARP_QUEUEING */
-    /* no empty or recyclable entries found */
-  } else {
-      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
-    return (s8_t)ERR_MEM;
-  }
+      /* recycle oldest stable*/
+      i = old_stable;
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
+      /* no queued packets should exist on stable entries */
+      LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
+    /* 3) found recyclable pending entry without queued packets? */
+    } else if (old_pending < ARP_TABLE_SIZE) {
+      /* recycle oldest pending */
+      i = old_pending;
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
+    /* 4) found recyclable pending entry with queued packets? */
+    } else if (old_queue < ARP_TABLE_SIZE) {
+      /* recycle oldest pending (queued packets are free in etharp_free_entry) */
+      i = old_queue;
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
+      /* no empty or recyclable entries found */
+    } else {
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n"));
+      return (s8_t)ERR_MEM;
+    }
 
-  /* { empty or recyclable entry found } */
-  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
-    free_entry(i);
+    /* { empty or recyclable entry found } */
+    LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
+    etharp_free_entry(i);
   }
 
   LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
@@ -392,9 +403,6 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
     ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
   }
   arp_table[i].ctime = 0;
-#if ETHARP_SUPPORT_STATIC_ENTRIES
-  arp_table[i].static_entry = 0;
-#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
   return (err_t)i;
 }
 
@@ -442,23 +450,23 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct
  * @see pbuf_free()
  */
 static err_t
-update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
+etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
 {
   s8_t i;
   LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
-  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
     ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
-                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
-                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
+    ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
+    ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
   /* non-unicast address? */
   if (ip_addr_isany(ipaddr) ||
       ip_addr_isbroadcast(ipaddr, netif) ||
       ip_addr_ismulticast(ipaddr)) {
-    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
     return ERR_ARG;
   }
   /* find or create ARP entry */
-  i = find_entry(ipaddr, flags);
+  i = etharp_find_entry(ipaddr, flags);
   /* bail out if no entry could be found */
   if (i < 0) {
     return (err_t)i;
@@ -467,27 +475,28 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
 #if ETHARP_SUPPORT_STATIC_ENTRIES
   if (flags & ETHARP_FLAG_STATIC_ENTRY) {
     /* record static type */
-    arp_table[i].static_entry = 1;
-  }
+    arp_table[i].state = ETHARP_STATE_STATIC;
+  } else
 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
-  
-  /* mark it stable */
-  arp_table[i].state = ETHARP_STATE_STABLE;
+  {
+    /* mark it stable */
+    arp_table[i].state = ETHARP_STATE_STABLE;
+  }
 
-#if LWIP_SNMP
   /* record network interface */
+#if LWIP_SNMP
   arp_table[i].netif = netif;
 #endif /* LWIP_SNMP */
   /* insert in SNMP ARP index tree */
   snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
 
-  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
   /* update address */
   ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
   /* reset time stamp */
   arp_table[i].ctime = 0;
-#if ARP_QUEUEING
   /* this is where we will send out queued packets! */
+#if ARP_QUEUEING
   while (arp_table[i].q != NULL) {
     struct pbuf *p;
     /* remember remainder of queue */
@@ -498,12 +507,16 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
     p = q->p;
     /* now queue entry can be freed */
     memp_free(MEMP_ARP_QUEUE, q);
+#else /* ARP_QUEUEING */
+  if (arp_table[i].q != NULL) {
+    struct pbuf *p = arp_table[i].q;
+    arp_table[i].q = NULL;
+#endif /* ARP_QUEUEING */
     /* send the queued IP packet */
     etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
     /* free the queued IP packet */
     pbuf_free(p);
   }
-#endif /* ARP_QUEUEING */
   return ERR_OK;
 }
 
@@ -530,7 +543,7 @@ etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
     return ERR_RTE;
   }
 
-  return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
+  return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
 }
 
 /** Remove a static entry from the ARP table previously added with a call to
@@ -549,19 +562,18 @@ etharp_remove_static_entry(ip_addr_t *ipaddr)
     ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
 
   /* find or create ARP entry */
-  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
   /* bail out if no entry could be found */
   if (i < 0) {
     return (err_t)i;
   }
 
-  if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
-    (arp_table[i].static_entry == 0)) {
+  if (arp_table[i].state != ETHARP_STATE_STATIC) {
     /* entry wasn't a static entry, cannot remove it */
     return ERR_ARG;
   }
   /* entry found, free it */
-  free_entry(i);
+  etharp_free_entry(i);
   return ERR_OK;
 }
 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
@@ -588,8 +600,8 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
 
   LWIP_UNUSED_ARG(netif);
 
-  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
-  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
+  if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
       *eth_ret = &arp_table[i].ethaddr;
       *ip_ret = &arp_table[i].ipaddr;
       return i;
@@ -618,6 +630,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
 {
   struct eth_hdr *ethhdr;
   struct ip_hdr *iphdr;
+  ip_addr_t iphdr_src;
   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
 
   /* Only insert an entry if the source IP address of the
@@ -625,13 +638,15 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
   ethhdr = (struct eth_hdr *)p->payload;
   iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
 #if ETHARP_SUPPORT_VLAN
-  if (ethhdr->type == ETHTYPE_VLAN) {
+  if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
     iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
   }
 #endif /* ETHARP_SUPPORT_VLAN */
 
+  ip_addr_copy(iphdr_src, iphdr->src);
+
   /* source is not on the local network? */
-  if (!ip_addr_netcmp(&(iphdr->src), &(netif->ip_addr), &(netif->netmask))) {
+  if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) {
     /* do nothing */
     return;
   }
@@ -640,7 +655,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
   /* update the source IP address in the cache, if present */
   /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
    * back soon (for example, if the destination IP address is ours. */
-  update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
+  etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
 }
 #endif /* ETHARP_TRUST_IP_MAC */
 
@@ -672,7 +687,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
 #endif /* LWIP_AUTOIP */
 
   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
-  
+
   /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
      since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
   if (p->len < SIZEOF_ETHARP_PACKET) {
@@ -688,7 +703,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
   ethhdr = (struct eth_hdr *)p->payload;
   hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
 #if ETHARP_SUPPORT_VLAN
-  if (ethhdr->type == ETHTYPE_VLAN) {
+  if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
     hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
   }
 #endif /* ETHARP_SUPPORT_VLAN */
@@ -697,11 +712,10 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
   if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
       (hdr->hwlen != ETHARP_HWADDR_LEN) ||
       (hdr->protolen != sizeof(ip_addr_t)) ||
-      (hdr->proto != PP_HTONS(ETHTYPE_IP)) ||
-      (ethhdr->type != PP_HTONS(ETHTYPE_ARP)))  {
+      (hdr->proto != PP_HTONS(ETHTYPE_IP)))  {
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
-      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
-      hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type));
+      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
+      hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
     ETHARP_STATS_INC(etharp.proterr);
     ETHARP_STATS_INC(etharp.drop);
     pbuf_free(p);
@@ -734,7 +748,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
          can result in directly sending the queued packets for this host.
      ARP message not directed to us?
       ->  update the source IP address in the cache, if present */
-  update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
+  etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
                    for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
 
   /* now act on the message itself */
@@ -811,6 +825,28 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
   pbuf_free(p);
 }
 
+/** Just a small helper function that sends a pbuf to an ethernet address
+ * in the arp_table specified by the index 'arp_idx'.
+ */
+static err_t
+etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
+{
+  LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE",
+              arp_table[arp_idx].state >= ETHARP_STATE_STABLE);
+  /* if arp table entry is about to expire: re-request it,
+     but only if its state is ETHARP_STATE_STABLE to prevent flooding the
+     network with ARP requests if this address is used frequently. */
+  if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && 
+      (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {
+    if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
+      arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;
+    }
+  }
+  
+  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
+    &arp_table[arp_idx].ethaddr);
+}
+
 /**
  * Resolve and fill-in Ethernet address header for outgoing IP packet.
  *
@@ -832,7 +868,13 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
 err_t
 etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
 {
-  struct eth_addr *dest, mcastaddr;
+  struct eth_addr *dest;
+  struct eth_addr mcastaddr;
+  ip_addr_t *dst_addr = ipaddr;
+
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  LWIP_ASSERT("q != NULL", q != NULL);
+  LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
 
   /* make room for Ethernet header - should not fail */
   if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
@@ -843,8 +885,48 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
     return ERR_BUF;
   }
 
-  /* assume unresolved Ethernet address */
-  dest = NULL;
+  /* outside local network? if so, this can neither be a global broadcast nor
+     a subnet broadcast. */
+  if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
+      !ip_addr_islinklocal(ipaddr)) {
+#if LWIP_AUTOIP
+    struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
+      sizeof(struct eth_hdr));
+    /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
+       a link-local source address must always be "directly to its destination
+       on the same physical link. The host MUST NOT send the packet to any
+       router for forwarding". */
+    if (!ip_addr_islinklocal(&iphdr->src))
+#endif /* LWIP_AUTOIP */
+    {
+      /* interface has default gateway? */
+      if (!ip_addr_isany(&netif->gw)) {
+        /* send to hardware address of default gateway IP address */
+        dst_addr = &(netif->gw);
+      /* no default gateway available */
+      } else {
+        /* no route to destination error (default gateway missing) */
+        return ERR_RTE;
+      }
+    }
+  }
+#if LWIP_NETIF_HWADDRHINT
+  if (netif->addr_hint != NULL) {
+    /* per-pcb cached entry was given */
+    u8_t etharp_cached_entry = *(netif->addr_hint);
+    if (etharp_cached_entry < ARP_TABLE_SIZE) {
+#endif /* LWIP_NETIF_HWADDRHINT */
+      if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
+          (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
+        /* the per-pcb-cached entry is stable and the right one! */
+        ETHARP_STATS_INC(etharp.cachehit);
+        return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
+      }
+#if LWIP_NETIF_HWADDRHINT
+    }
+  }
+#endif /* LWIP_NETIF_HWADDRHINT */
+
   /* Determine on destination hardware address. Broadcasts and multicasts
    * are special, other IP addresses are looked up in the ARP table. */
 
@@ -855,9 +937,9 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
   /* multicast destination IP address? */
   } else if (ip_addr_ismulticast(ipaddr)) {
     /* Hash IP multicast address to MAC address.*/
-    mcastaddr.addr[0] = 0x01;
-    mcastaddr.addr[1] = 0x00;
-    mcastaddr.addr[2] = 0x5e;
+    mcastaddr.addr[0] = LL_MULTICAST_ADDR_0;
+    mcastaddr.addr[1] = LL_MULTICAST_ADDR_1;
+    mcastaddr.addr[2] = LL_MULTICAST_ADDR_2;
     mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
     mcastaddr.addr[4] = ip4_addr3(ipaddr);
     mcastaddr.addr[5] = ip4_addr4(ipaddr);
@@ -865,38 +947,20 @@ etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
     dest = &mcastaddr;
   /* unicast destination IP address? */
   } else {
-    /* outside local network? */
-    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
-        !ip_addr_islinklocal(ipaddr)) {
-      /* interface has default gateway? */
-      if (!ip_addr_isany(&netif->gw)) {
-        /* send to hardware address of default gateway IP address */
-        ipaddr = &(netif->gw);
-      /* no default gateway available */
-      } else {
-        /* no route to destination error (default gateway missing) */
-        return ERR_RTE;
-      }
-    }
-#if LWIP_NETIF_HWADDRHINT
-    if (netif->addr_hint != NULL) {
-      /* per-pcb cached entry was given */
-      u8_t etharp_cached_entry = *(netif->addr_hint);
-      if (etharp_cached_entry < ARP_TABLE_SIZE) {
-#endif /* LWIP_NETIF_HWADDRHINT */
-        if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
-            (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
-          /* the per-pcb-cached entry is stable and the right one! */
-          ETHARP_STATS_INC(etharp.cachehit);
-          return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
-            &arp_table[etharp_cached_entry].ethaddr);
-        }
-#if LWIP_NETIF_HWADDRHINT
+    s8_t i;
+    /* find stable entry: do this here since this is a critical path for
+       throughput and etharp_find_entry() is kind of slow */
+    for (i = 0; i < ARP_TABLE_SIZE; i++) {
+      if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
+          (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
+        /* found an existing, stable entry */
+        ETHARP_SET_HINT(netif, i);
+        return etharp_output_to_arp_index(netif, q, i);
       }
     }
-#endif /* LWIP_NETIF_HWADDRHINT */
-    /* queue on destination Ethernet address belonging to ipaddr */
-    return etharp_query(netif, ipaddr, q);
+    /* no stable entry found, use the (slower) query function:
+       queue on destination Ethernet address belonging to ipaddr */
+    return etharp_query(netif, dst_addr, q);
   }
 
   /* continuation for multicast/broadcast destinations */
@@ -954,7 +1018,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
   }
 
   /* find entry in ARP cache, ask to create entry if queueing packet */
-  i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
+  i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
 
   /* could not find or create entry? */
   if (i < 0) {
@@ -974,7 +1038,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
   /* { i is either a STABLE or (new or existing) PENDING entry } */
   LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
   ((arp_table[i].state == ETHARP_STATE_PENDING) ||
-   (arp_table[i].state == ETHARP_STATE_STABLE)));
+   (arp_table[i].state >= ETHARP_STATE_STABLE)));
 
   /* do we have a pending entry? or an implicit query request? */
   if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
@@ -990,85 +1054,91 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
       return result;
     }
   }
-  
+
   /* packet given? */
   LWIP_ASSERT("q != NULL", q != NULL);
-    /* stable entry? */
-    if (arp_table[i].state == ETHARP_STATE_STABLE) {
-      /* we have a valid IP->Ethernet address mapping */
+  /* stable entry? */
+  if (arp_table[i].state >= ETHARP_STATE_STABLE) {
+    /* we have a valid IP->Ethernet address mapping */
     ETHARP_SET_HINT(netif, i);
-      /* send the packet */
-      result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
-    /* pending entry? (either just created or already pending */
-    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
-#if ARP_QUEUEING /* queue the given q packet */
-      struct pbuf *p;
-      int copy_needed = 0;
-      /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
-       * to copy the whole queue into a new PBUF_RAM (see bug #11400) 
-       * PBUF_ROMs can be left as they are, since ROM must not get changed. */
-      p = q;
-      while (p) {
-        LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
-        if(p->type != PBUF_ROM) {
-          copy_needed = 1;
-          break;
-        }
-        p = p->next;
+    /* send the packet */
+    result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
+  /* pending entry? (either just created or already pending */
+  } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+    /* entry is still pending, queue the given packet 'q' */
+    struct pbuf *p;
+    int copy_needed = 0;
+    /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
+     * to copy the whole queue into a new PBUF_RAM (see bug #11400) 
+     * PBUF_ROMs can be left as they are, since ROM must not get changed. */
+    p = q;
+    while (p) {
+      LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
+      if(p->type != PBUF_ROM) {
+        copy_needed = 1;
+        break;
       }
-      if(copy_needed) {
-        /* copy the whole packet into new pbufs */
-        p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
-        if(p != NULL) {
-          if (pbuf_copy(p, q) != ERR_OK) {
-            pbuf_free(p);
-            p = NULL;
-          }
+      p = p->next;
+    }
+    if(copy_needed) {
+      /* copy the whole packet into new pbufs */
+      p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
+      if(p != NULL) {
+        if (pbuf_copy(p, q) != ERR_OK) {
+          pbuf_free(p);
+          p = NULL;
         }
-      } else {
-        /* referencing the old pbuf is enough */
-        p = q;
-        pbuf_ref(p);
       }
-      /* packet could be taken over? */
-      if (p != NULL) {
-        /* queue packet ... */
-        struct etharp_q_entry *new_entry;
-        /* allocate a new arp queue entry */
+    } else {
+      /* referencing the old pbuf is enough */
+      p = q;
+      pbuf_ref(p);
+    }
+    /* packet could be taken over? */
+    if (p != NULL) {
+      /* queue packet ... */
+#if ARP_QUEUEING
+      struct etharp_q_entry *new_entry;
+      /* allocate a new arp queue entry */
       new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
-        if (new_entry != NULL) {
-          new_entry->next = 0;
-          new_entry->p = p;
-          if(arp_table[i].q != NULL) {
-            /* queue was already existent, append the new entry to the end */
-            struct etharp_q_entry *r;
-            r = arp_table[i].q;
-            while (r->next != NULL) {
-              r = r->next;
-            }
-            r->next = new_entry;
-          } else {
-            /* queue did not exist, first item in queue */
-            arp_table[i].q = new_entry;
+      if (new_entry != NULL) {
+        new_entry->next = 0;
+        new_entry->p = p;
+        if(arp_table[i].q != NULL) {
+          /* queue was already existent, append the new entry to the end */
+          struct etharp_q_entry *r;
+          r = arp_table[i].q;
+          while (r->next != NULL) {
+            r = r->next;
           }
-          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
-          result = ERR_OK;
+          r->next = new_entry;
         } else {
-          /* the pool MEMP_ARP_QUEUE is empty */
-          pbuf_free(p);
-          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
-          /* { result == ERR_MEM } through initialization */
+          /* queue did not exist, first item in queue */
+          arp_table[i].q = new_entry;
         }
+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+        result = ERR_OK;
       } else {
-        ETHARP_STATS_INC(etharp.memerr);
+        /* the pool MEMP_ARP_QUEUE is empty */
+        pbuf_free(p);
         LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
-        /* { result == ERR_MEM } through initialization */
+        result = ERR_MEM;
       }
 #else /* ARP_QUEUEING */
-      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
-      /* { result == ERR_MEM } through initialization */
-      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
+      /* always queue one packet per ARP request only, freeing a previously queued packet */
+      if (arp_table[i].q != NULL) {
+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+        pbuf_free(arp_table[i].q);
+      }
+      arp_table[i].q = p;
+      result = ERR_OK;
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
 #endif /* ARP_QUEUEING */
+    } else {
+      ETHARP_STATS_INC(etharp.memerr);
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
+      result = ERR_MEM;
+    }
   }
   return result;
 }
@@ -1106,6 +1176,8 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
   const u8_t * ethdst_hwaddr;
 #endif /* LWIP_AUTOIP */
 
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+
   /* allocate a pbuf for the outgoing ARP request packet */
   p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
   /* could allocate a pbuf for an ARP request? */
@@ -1131,10 +1203,10 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
    * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
   ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;
 #endif /* LWIP_AUTOIP */
-    /* Write the ARP MAC-Addresses */
+  /* Write the ARP MAC-Addresses */
   ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
   ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
-    /* Write the Ethernet MAC-Addresses */
+  /* Write the Ethernet MAC-Addresses */
 #if LWIP_AUTOIP
   ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
 #else  /* LWIP_AUTOIP */
@@ -1196,6 +1268,14 @@ ethernet_input(struct pbuf *p, struct netif *netif)
 {
   struct eth_hdr* ethhdr;
   u16_t type;
+  s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
+
+  if (p->len <= SIZEOF_ETH_HDR) {
+    /* a packet with only an ethernet header (or less) is not valid for us */
+    ETHARP_STATS_INC(etharp.proterr);
+    ETHARP_STATS_INC(etharp.drop);
+    goto free_and_return;
+  }
 
   /* points to packet payload, which starts with an Ethernet header */
   ethhdr = (struct eth_hdr *)p->payload;
@@ -1211,14 +1291,25 @@ ethernet_input(struct pbuf *p, struct netif *netif)
 #if ETHARP_SUPPORT_VLAN
   if (type == PP_HTONS(ETHTYPE_VLAN)) {
     struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
-#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
+    if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
+      /* a packet with only an ethernet/vlan header (or less) is not valid for us */
+      ETHARP_STATS_INC(etharp.proterr);
+      ETHARP_STATS_INC(etharp.drop);
+      goto free_and_return;
+    }
+#if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
+#ifdef ETHARP_VLAN_CHECK_FN
+    if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
+#elif defined(ETHARP_VLAN_CHECK)
     if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
+#endif
       /* silently ignore this packet: not for our VLAN */
       pbuf_free(p);
       return ERR_OK;
     }
-#endif /* ETHARP_VLAN_CHECK */
+#endif /* defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
     type = vlan->tpid;
+    ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
   }
 #endif /* ETHARP_SUPPORT_VLAN */
 
@@ -1226,6 +1317,20 @@ ethernet_input(struct pbuf *p, struct netif *netif)
   netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
 #endif /* LWIP_ARP_FILTER_NETIF*/
 
+  if (ethhdr->dest.addr[0] & 1) {
+    /* this might be a multicast or broadcast packet */
+    if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) {
+      if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) &&
+          (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) {
+        /* mark the pbuf as link-layer multicast */
+        p->flags |= PBUF_FLAG_LLMCAST;
+      }
+    } else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
+      /* mark the pbuf as link-layer broadcast */
+      p->flags |= PBUF_FLAG_LLBCAST;
+    }
+  }
+
   switch (type) {
 #if LWIP_ARP
     /* IP packet? */
@@ -1238,7 +1343,7 @@ ethernet_input(struct pbuf *p, struct netif *netif)
       etharp_ip_input(netif, p);
 #endif /* ETHARP_TRUST_IP_MAC */
       /* skip Ethernet header */
-      if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
+      if(pbuf_header(p, -ip_hdr_offset)) {
         LWIP_ASSERT("Can't move over header in packet", 0);
         goto free_and_return;
       } else {
@@ -1265,6 +1370,19 @@ ethernet_input(struct pbuf *p, struct netif *netif)
       break;
 #endif /* PPPOE_SUPPORT */
 
+#if LWIP_IPV6
+    case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
+      /* skip Ethernet header */
+      if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) {
+        LWIP_ASSERT("Can't move over header in packet", 0);
+        goto free_and_return;
+      } else {
+        /* pass to IPv6 layer */
+        ip6_input(p, netif);
+      }
+      break;
+#endif /* LWIP_IPV6 */
+
     default:
       ETHARP_STATS_INC(etharp.proterr);
       ETHARP_STATS_INC(etharp.drop);
index a5b7d990b11eddddc5cdb81c5263f813aa2ca7e0..46900bdbfc26c205b68677dd98b368031e8acdaf 100644 (file)
@@ -50,9 +50,9 @@
 #include "lwip/def.h"
 #include "lwip/mem.h"
 #include "lwip/pbuf.h"
-#include "lwip/sys.h"
-#include <lwip/stats.h>
-#include <lwip/snmp.h>
+#include "lwip/stats.h"
+#include "lwip/snmp.h"
+#include "lwip/ethip6.h"
 #include "netif/etharp.h"
 #include "netif/ppp_oe.h"
 
@@ -239,6 +239,7 @@ ethernetif_input(struct netif *netif)
   switch (htons(ethhdr->type)) {
   /* IP or ARP packet? */
   case ETHTYPE_IP:
+  case ETHTYPE_IPV6:
   case ETHTYPE_ARP:
 #if PPPOE_SUPPORT
   /* PPPoE packet? */
@@ -305,6 +306,9 @@ ethernetif_init(struct netif *netif)
    * from it if you have to do some checks before sending (e.g. if link
    * is available...) */
   netif->output = etharp_output;
+#if LWIP_IPV6
+  netif->output_ip6 = ethip6_output;
+#endif /* LWIP_IPV6 */
   netif->linkoutput = low_level_output;
   
   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
index 5cc8360a986c56ca4ec1ad89624b01d625f59c3b..c3c49d22a2547b3ac626304f7da5fd2992e2af0d 100644 (file)
@@ -408,7 +408,7 @@ link_down(int unit)
 {
   int i;
   struct protent *protp;
-  
+
   AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit));
 
   if (did_authup) {
@@ -472,7 +472,7 @@ link_established(int unit)
       return;
     }
   }
-    
+
   lcp_phase[unit] = PHASE_AUTHENTICATE;
   auth = 0;
 #if CHAP_SUPPORT
@@ -588,7 +588,7 @@ void
 auth_peer_success(int unit, u16_t protocol, char *name, int namelen)
 {
   int pbit;
-  
+
   AUTHDEBUG(LOG_INFO, ("auth_peer_success: %d proto=%X\n", unit, protocol));
   switch (protocol) {
     case PPP_CHAP:
@@ -601,7 +601,7 @@ auth_peer_success(int unit, u16_t protocol, char *name, int namelen)
       AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol));
       return;
   }
-  
+
   /*
    * Save the authenticated name of the peer for later.
    */
@@ -627,7 +627,7 @@ void
 auth_withpeer_fail(int unit, u16_t protocol)
 {
   int errCode = PPPERR_AUTHFAIL;
-  
+
   LWIP_UNUSED_ARG(protocol);
 
   AUTHDEBUG(LOG_INFO, ("auth_withpeer_fail: %d proto=%X\n", unit, protocol));
@@ -651,7 +651,7 @@ void
 auth_withpeer_success(int unit, u16_t protocol)
 {
   int pbit;
-  
+
   AUTHDEBUG(LOG_INFO, ("auth_withpeer_success: %d proto=%X\n", unit, protocol));
   switch (protocol) {
     case PPP_CHAP:
@@ -667,7 +667,7 @@ auth_withpeer_success(int unit, u16_t protocol)
       AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol));
       pbit = 0;
   }
-  
+
   /*
    * If there is no more authentication still being done,
    * proceed to the network (or callback) phase.
@@ -697,7 +697,7 @@ np_up(int unit, u16_t proto)
     if (ppp_settings.idle_time_limit > 0) {
       TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);
     }
-    
+
     /*
      * Set a timeout to close the connection once the maximum
      * connect time has expired.
@@ -968,16 +968,16 @@ plogin(char *user, char *passwd, char **msg, int *msglen)
 
 
 
-  
 
 
 
-  
 
 
 
 
-  
+
+
+
 
 
 
@@ -1267,7 +1267,7 @@ static void
 free_wordlist(struct wordlist *wp)
 {
   struct wordlist *next;
-  
+
   while (wp != NULL) {
     next = wp->next;
     free(wp);
index fda2b1c018c30ae2004855ec457210ea5884fadf..3a49ff8a5e4a0970af46367d5dd7a5263600477e 100644 (file)
@@ -429,7 +429,7 @@ ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len)
   char rhostname[256];
   MD5_CTX mdContext;
   u_char hash[MD5_SIGNATURE_SIZE];
-  
+
   CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id));
   if (cstate->clientstate == CHAPCS_CLOSED ||
     cstate->clientstate == CHAPCS_PENDING) {
@@ -527,7 +527,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
   MD5_CTX mdContext;
   char secret[MAXSECRETLEN];
   u_char hash[MD5_SIGNATURE_SIZE];
-  
+
   CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id));
   
   if (cstate->serverstate == CHAPSS_CLOSED ||
@@ -588,7 +588,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
   if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
                   secret, &secret_len, 1)) {
     CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n",
-    rhostname));
+               rhostname));
   } else {
     /*  generate MD based on negotiated type */
     switch (cstate->chal_type) {
@@ -717,21 +717,21 @@ ChapSendChallenge(chap_state *cstate)
   name_len = (int)strlen(cstate->chal_name);
   outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
   outp = outpacket_buf[cstate->unit];
-  
+
   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 */
   
   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
-  
+
   CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
   
   TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
@@ -748,17 +748,17 @@ ChapSendStatus(chap_state *cstate, int code)
   u_char *outp;
   int outlen, msglen;
   char msg[256]; /* @todo: this can be a char*, no strcpy needed */
-  
+
   if (code == CHAP_SUCCESS) {
     strcpy(msg, "Welcome!");
   } else {
     strcpy(msg, "I don't like you.  Go 'way.");
   }
   msglen = (int)strlen(msg);
-  
+
   outlen = CHAP_HEADERLEN + msglen;
   outp = outpacket_buf[cstate->unit];
-  
+
   MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */
   
   PUTCHAR(code, outp);
@@ -766,7 +766,7 @@ ChapSendStatus(chap_state *cstate, int code)
   PUTSHORT(outlen, outp);
   BCOPY(msg, outp, msglen);
   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
-  
+
   CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code,
              cstate->chal_id));
 }
@@ -784,7 +784,7 @@ ChapGenChallenge(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)
@@ -795,7 +795,7 @@ ChapGenChallenge(chap_state *cstate)
   cstate->chal_len = (u_char)chal_len;
   cstate->chal_id = ++cstate->id;
   cstate->chal_transmits = 0;
-  
+
   /* generate a random string */
   for (i = 0; i < chal_len; i++ ) {
     *ptr++ = (char) (magic() & 0xff);
@@ -812,12 +812,12 @@ ChapSendResponse(chap_state *cstate)
 {
   u_char *outp;
   int outlen, md_len, name_len;
-  
+
   md_len = cstate->resp_length;
   name_len = (int)strlen(cstate->resp_name);
   outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
   outp = outpacket_buf[cstate->unit];
-  
+
   MAKEHEADER(outp, PPP_CHAP);
   
   PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */
@@ -827,12 +827,12 @@ ChapSendResponse(chap_state *cstate)
   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 */
   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
-  
+
   cstate->clientstate = CHAPCS_RESPONSE;
   TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
   ++cstate->resp_transmits;
@@ -851,7 +851,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *
   int code, id, len;
   int clen, nlen;
   u_char x;
-  
+
   if (plen < CHAP_HEADERLEN) {
     return 0;
   }
index c2ab2e39729bfb71a837ae4862f698b23922d2e3..2e73c5af8ffdc6faf6d310cecfeb12519f5b7bdd 100644 (file)
@@ -143,7 +143,7 @@ fsm_lowerup(fsm *f)
       FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
   }
-  
+
   FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
 }
@@ -332,7 +332,7 @@ fsm_timeout(void *arg)
         f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
         if( f->callbacks->finished ) {
           (*f->callbacks->finished)(f);
-  }
+        }
       } else {
         FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
index 2b719b819846a78a9ba4e7b329c16f0ccc877633..461a600f85c22cb1b35c5d783f1cc5db32736bec 100644 (file)
@@ -157,7 +157,7 @@ static void ipcp_clear_addrs (int);
 
 /*
  * 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. */
@@ -526,7 +526,7 @@ ipcp_ackci(fsm *f, u_char *p, int len)
     goto bad;
   }
   return (1);
-  
+
 bad:
   IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n"));
   return (0);
index 24bb502e88aa7adf784cc29d1815bf1a1196c070..21c83ac44490b6c4e69adff43fffb878e590bf08 100644 (file)
@@ -242,13 +242,13 @@ lcp_init(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);
-  
+
   wo->passive           = 0;
   wo->silent            = 0;
   wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */
@@ -264,7 +264,7 @@ lcp_init(int unit)
   wo->neg_accompression = 1;
   wo->neg_lqr           = 0;               /* no LQR implementation yet */
   wo->neg_cbcp          = 0;
-  
+
   ao->neg_mru           = 1;
   ao->mru               = PPP_MAXMRU;
   ao->neg_asyncmap      = 1;
@@ -426,10 +426,10 @@ lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)
     case ECHOREP:
       lcp_received_echo_reply(f, id, inp, len);
       break;
-    
+
     case DISCREQ:
       break;
-    
+
     default:
       return 0;
   }
@@ -1992,7 +1992,7 @@ lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)
     LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n"));
     return;
   }
-  
+
   /* Reset the number of outstanding echo frames */
   lcp_echos_pending = 0;
 }
index 3783b7ede73eb112157475f8afde54735fc1bf7b..78ef490a5430de78da784c18b9790b130659d444 100644 (file)
@@ -136,7 +136,7 @@ static void
 upap_init(int unit)
 {
   upap_state *u = &upap[unit];
-  
+
   UPAPDEBUG(LOG_INFO, ("upap_init: %d\n", unit));
   u->us_unit         = unit;
   u->us_user         = NULL;
@@ -218,7 +218,7 @@ upap_timeout(void *arg)
         u->us_unit, u->us_timeouttime, u->us_clientstate));
 
   if (u->us_clientstate != UPAPCS_AUTHREQ) {
-       UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
+    UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
     return;
   }
 
@@ -483,15 +483,15 @@ upap_rauthack(upap_state *u, u_char *inp, int id, int len)
   if (len < (int)sizeof (u_char)) {
     UPAPDEBUG(LOG_INFO, ("pap_rauthack: ignoring missing msg-length.\n"));
   } else {
-  GETCHAR(msglen, inp);
+    GETCHAR(msglen, inp);
     if (msglen > 0) {
-  len -= sizeof (u_char);
-  if (len < msglen) {
+      len -= sizeof (u_char);
+      if (len < msglen) {
         UPAPDEBUG(LOG_INFO, ("pap_rauthack: rcvd short packet.\n"));
-    return;
-  }
-  msg = (char *) inp;
-  PRINTMSG(msg, msglen);
+        return;
+      }
+      msg = (char *) inp;
+      PRINTMSG(msg, msglen);
     }
   }
   UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */
index 5e2dea00e5ba950e6edee23dacedde2479fd64e8..e9b433b053463e365dc7836a515d69cc4046b9d3 100644 (file)
@@ -344,7 +344,9 @@ static void
 pppRecvWakeup(int pd)
 {
   PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd));
-  sio_read_abort(pppControl[pd].fd);
+  if (pppControl[pd].openFlag != 0) {
+    sio_read_abort(pppControl[pd].fd);
+  }
 }
 #endif /* PPPOS_SUPPORT */
 
@@ -363,7 +365,6 @@ pppLinkTerminated(int pd)
     PPPControl* pc;
     pppRecvWakeup(pd);
     pc = &pppControl[pd];
-    pppDrop(&pc->rx); /* bug fix #17726 */
 
     PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));
     if (pc->linkStatusCB) {
@@ -439,7 +440,7 @@ pppInit(void)
 
   magicInit();
 
-  subnetMask = PP_HTONL(0xffffff00);
+  subnetMask = PP_HTONL(0xffffff00UL);
 
   for (i = 0; i < NUM_PPP; i++) {
     /* Initialize each protocol to the standard option set. */
@@ -681,20 +682,8 @@ pppClose(int pd)
 void
 pppSigHUP(int pd)
 {
-#if PPPOE_SUPPORT
-  PPPControl *pc = &pppControl[pd];
-  if(pc->ethif) {
-    PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
-    pppHup(pd);
-  } else
-#endif /* PPPOE_SUPPORT */
-  {
-#if PPPOS_SUPPORT
-    PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
-    pppHup(pd);
-    pppRecvWakeup(pd);
-#endif /* PPPOS_SUPPORT */
-  }
+  PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));
+  pppHup(pd);
 }
 
 #if PPPOS_SUPPORT
@@ -1523,11 +1512,11 @@ pppInputThread(void *arg)
     count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE);
     if(count > 0) {
       pppInProc(pcrx, pcrx->rxbuf, count);
-      } else {
+    } else {
       /* nothing received, give other tasks a chance to run */
       sys_msleep(1);
-      }
     }
+  }
 }
 #endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */
 
@@ -1704,8 +1693,8 @@ pppInput(void *arg)
       }
 #if BYTE_ORDER == LITTLE_ENDIAN
       protocol = htons(protocol);
-      SMEMCPY(nb->payload, &protocol, sizeof(protocol));
 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
+      SMEMCPY(nb->payload, &protocol, sizeof(protocol));
       lcp_sprotrej(pd, nb->payload, nb->len);
     }
     break;
@@ -1774,7 +1763,7 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
   PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l));
   while (l-- > 0) {
     curChar = *s++;
-    
+
     SYS_ARCH_PROTECT(lev);
     escaped = ESCAPE_P(pcrx->inACCM, curChar);
     SYS_ARCH_UNPROTECT(lev);
@@ -1789,59 +1778,62 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
         pcrx->inEscaped = 1;
       /* Check for the flag character. */
       } else if (curChar == PPP_FLAG) {
-         /* If this is just an extra flag character, ignore it. */
+        /* If this is just an extra flag character, ignore it. */
         if (pcrx->inState <= PDADDRESS) {
-           /* ignore it */;
-         /* If we haven't received the packet header, drop what has come in. */
+          /* ignore it */;
+        /* If we haven't received the packet header, drop what has come in. */
         } else if (pcrx->inState < PDDATA) {
           PPPDEBUG(LOG_WARNING,
                    ("pppInProc[%d]: Dropping incomplete packet %d\n", 
                     pcrx->pd, pcrx->inState));
-           LINK_STATS_INC(link.lenerr);
+          LINK_STATS_INC(link.lenerr);
           pppDrop(pcrx);
-         /* If the fcs is invalid, drop the packet. */
+        /* If the fcs is invalid, drop the packet. */
         } else if (pcrx->inFCS != PPP_GOODFCS) {
           PPPDEBUG(LOG_INFO,
                    ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", 
                     pcrx->pd, pcrx->inFCS, pcrx->inProtocol));
           /* Note: If you get lots of these, check for UART frame errors or try different baud rate */
-           LINK_STATS_INC(link.chkerr);
+          LINK_STATS_INC(link.chkerr);
           pppDrop(pcrx);
-         /* Otherwise it's a good packet so pass it on. */
-         } else {
-           /* Trim off the checksum. */
+        /* Otherwise it's a good packet so pass it on. */
+        } else {
+          struct pbuf *inp;
+          /* Trim off the checksum. */
           if(pcrx->inTail->len >= 2) {
             pcrx->inTail->len -= 2;
 
             pcrx->inTail->tot_len = pcrx->inTail->len;
             if (pcrx->inTail != pcrx->inHead) {
               pbuf_cat(pcrx->inHead, pcrx->inTail);
-             }
-           } else {
+            }
+          } else {
             pcrx->inTail->tot_len = pcrx->inTail->len;
             if (pcrx->inTail != pcrx->inHead) {
               pbuf_cat(pcrx->inHead, pcrx->inTail);
-             }
+            }
 
             pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2);
-           }
+          }
 
-           /* Dispatch the packet thereby consuming it. */
+          /* Dispatch the packet thereby consuming it. */
+          inp = pcrx->inHead;
+          /* Packet consumed, release our references. */
+          pcrx->inHead = NULL;
+          pcrx->inTail = NULL;
 #if PPP_INPROC_MULTITHREADED
-          if(tcpip_callback_with_block(pppInput, pcrx->inHead, 0) != ERR_OK) {
+          if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) {
             PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd));
-            pbuf_free(pcrx->inHead);
-             LINK_STATS_INC(link.drop);
+            pbuf_free(inp);
+            LINK_STATS_INC(link.drop);
             snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif);
-           }
+          }
 #else /* PPP_INPROC_MULTITHREADED */
-          pppInput(pcrx->inHead);
+          pppInput(inp);
 #endif /* PPP_INPROC_MULTITHREADED */
-          pcrx->inHead = NULL;
-          pcrx->inTail = NULL;
-         }
+        }
 
-         /* Prepare for a new packet. */
+        /* Prepare for a new packet. */
         pcrx->inFCS = PPP_INITFCS;
         pcrx->inState = PDADDRESS;
         pcrx->inEscaped = 0;
@@ -1912,10 +1904,12 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
         case PDDATA:                    /* Process data byte. */
           /* Make space to receive processed data. */
           if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) {
-            if(pcrx->inTail) {
+            if (pcrx->inTail != NULL) {
               pcrx->inTail->tot_len = pcrx->inTail->len;
               if (pcrx->inTail != pcrx->inHead) {
                 pbuf_cat(pcrx->inHead, pcrx->inTail);
+                /* give up the inTail reference now */
+                pcrx->inTail = NULL;
               }
             }
             /* If we haven't started a packet, we need a packet header. */
@@ -1949,7 +1943,7 @@ pppInProc(PPPControlRx *pcrx, u_char *s, int l)
 
       /* update the frame check sequence number. */
       pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
-  }
+    }
   } /* while (l-- > 0), all bytes processed */
 
   avRandomize();
index 968feb94a3d052878ce1523975d5e8f090c7d24e..c908a1e423fa1bd6c19e36397628df13d3aaf17a 100644 (file)
 
 #include "lwip/def.h"
 #include "lwip/pbuf.h"
-#include "lwip/sys.h"
 #include "lwip/stats.h"
 #include "lwip/snmp.h"
 #include "lwip/sio.h"
+#if !NO_SYS
+#include "lwip/sys.h"
+#endif
 
 #define SLIP_BLOCK     1
 #define SLIP_DONTBLOCK 0
@@ -157,7 +159,7 @@ slip_sio_read(sio_fd_t fd, u8_t* data, u32_t len, u8_t block)
  * @param block if 1, block until data is received; if 0, return when all data
  *        from the buffer is received (multiple calls to this function will
  *        return a complete packet, NULL is returned before - used for polling)
- * @return The IP packet when SLIP_END is received 
+ * @return The IP packet when SLIP_END is received
  */
 static struct pbuf *
 slipif_input(struct netif *netif, u8_t block)
@@ -174,23 +176,23 @@ slipif_input(struct netif *netif, u8_t block)
   while (slip_sio_read(priv->sd, &c, 1, block) > 0) {
     switch (priv->state) {
     case SLIP_RECV_NORMAL:
-    switch (c) {
-    case SLIP_END:
+      switch (c) {
+      case SLIP_END:
         if (priv->recved > 0) {
-        /* Received whole packet. */
-        /* Trim the pbuf to the size of the received packet. */
+          /* Received whole packet. */
+          /* Trim the pbuf to the size of the received packet. */
           pbuf_realloc(priv->q, priv->recved);
-        
-        LINK_STATS_INC(link.recv);
-        
-        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
+
+          LINK_STATS_INC(link.recv);
+
+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
           t = priv->q;
           priv->p = priv->q = NULL;
           priv->i = priv->recved = 0;
           return t;
-      }
+        }
         continue;
-    case SLIP_ESC:
+      case SLIP_ESC:
         priv->state = SLIP_RECV_ESCAPE;
         continue;
       }
@@ -208,27 +210,27 @@ slipif_input(struct netif *netif, u8_t block)
       /* FALLTHROUGH */
     }
 
-      /* byte received, packet not yet completely received */
+    /* byte received, packet not yet completely received */
     if (priv->p == NULL) {
-        /* allocate a new pbuf */
-        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
+      /* allocate a new pbuf */
+      LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
       priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
 
       if (priv->p == NULL) {
-          LINK_STATS_INC(link.drop);
-          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
-          /* don't process any further since we got no pbuf to receive to */
-          break;
-        }
+        LINK_STATS_INC(link.drop);
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
+        /* don't process any further since we got no pbuf to receive to */
+        break;
+      }
 
       if (priv->q != NULL) {
-          /* 'chain' the pbuf to the existing chain */
+        /* 'chain' the pbuf to the existing chain */
         pbuf_cat(priv->q, priv->p);
-        } else {
-          /* p is the first pbuf in the chain */
+      } else {
+        /* p is the first pbuf in the chain */
         priv->q = priv->p;
-        }
       }
+    }
 
     /* this automatically drops bytes if > SLIP_MAX_SIZE */
     if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
@@ -236,18 +238,18 @@ slipif_input(struct netif *netif, u8_t block)
       priv->recved++;
       priv->i++;
       if (priv->i >= priv->p->len) {
-          /* on to the next pbuf */
+        /* on to the next pbuf */
         priv->i = 0;
         if (priv->p->next != NULL && priv->p->next->len > 0) {
-            /* p is a chain, on to the next in the chain */
+          /* p is a chain, on to the next in the chain */
             priv->p = priv->p->next;
-          } else {
-            /* p is a single pbuf, set it to NULL so next time a new
-             * pbuf is allocated */
+        } else {
+          /* p is a single pbuf, set it to NULL so next time a new
+           * pbuf is allocated */
             priv->p = NULL;
-          }
         }
       }
+    }
   }
 
   return NULL;
@@ -335,9 +337,11 @@ slipif_init(struct netif *netif)
    */
   NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);
 
+#if !NO_SYS
   /* Create a thread to poll the serial line. */
   sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
     SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
+#endif
   return ERR_OK;
 }
 
index 79e86cff2244db0c473bbeea627e7171418abb38..927a7989c470ed885a45aa681336ea77a5a68f81 100644 (file)
@@ -1,5 +1,3 @@
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 #include "device"
 #include <cstring>
 #include <cstdio>
@@ -8,7 +6,7 @@
 
 void Ankh::Device_manager::add_device(void *ptr)
 {
-//     L4::cout << "Add device @ " << ptr << "\n";
+//     std::cout << "Add device @ " << ptr << "\n";
        _devices.push_back(new Device(ptr));
 }
 
index b7bfb3a41e107f37578917c4070e448736d58745..a86f4a8a77b58fd54a53389ccc0b8b77036c5c4b 100644 (file)
@@ -13,8 +13,7 @@
 #include <l4/re/protocols>
 #include <l4/re/util/meta>
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
+#include <l4/cxx/std_exc_io>
 #include <l4/dde/linux26/dde26.h>
 
 #include <l4/sys/debugger.h>
@@ -26,7 +25,7 @@
 
 static L4Re::Util::Registry_server<> server;
 
-int Ankh::ServerSession::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+int Ankh::ServerSession::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
        l4_msgtag_t t;
        ios >> t;
@@ -62,11 +61,11 @@ int Ankh::ServerSession::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
 class Ankh_server : public L4::Server_object
 {
        public: 
-               int dispatch(l4_umword_t, L4::Ipc_iostream &ios);
+               int dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
 };
 
 
-int Ankh_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+int Ankh_server::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
        l4_msgtag_t t;
        ios >> t;
@@ -113,7 +112,7 @@ int Ankh_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
                                }
                                else
                                {
-                                       L4::cerr << "Error creating Ankh session object.\n";
+                                       std::cerr << "Error creating Ankh session object.\n";
                                        return -L4_ENOMEM;
                                }
                        }
@@ -201,7 +200,7 @@ int main()
        }
        catch (L4::Base_exception const &e)
        {
-               L4::cerr << "Error: " << e << '\n';
+               std::cerr << "Error: " << e << '\n';
                return -1;
        }
        catch (std::exception const &e)
index 4e40d4c68b32eb5ebfda977fc2fe0e84763a7e6a..755d6b990f31794789f120d5e056a0a7129ab8c4 100644 (file)
@@ -139,7 +139,7 @@ namespace Ankh
                        static int count;
 
                public:
-                       int dispatch(l4_umword_t, L4::Ipc_iostream &ios);
+                       int dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
 
                        ServerSession(bool want_phys, bool promisc,bool debug,
                                      char const *name, char const *shmname, unsigned bufsize,
index 6d88f6eb34005c10af1fd85e4047cf2f90a813e6..a950cf3036b851018b5d7caeb015c372f4ade30e 100644 (file)
@@ -4,7 +4,7 @@
 ENTRY(_start)
 
 PHDRS {
-  data PT_LOAD;
+  common PT_LOAD;
 #ifdef IMAGE_MODE
   mods PT_LOAD;
 #endif
@@ -14,11 +14,16 @@ SECTIONS
 {
   . = LINKADDR;
   /* Merge .text, .rodata, and .data in one segment to save space */
-  .data :
+  .text :
   {
+       _stext = .;
     *(.init)
-    *(.text .text.* .gnu.linkonce.t*)
-    *(.rodata*)
+    *(.text .text.* .gnu.linkonce.t.*)
+  } : common
+
+  .data :
+  {
+    *(.rodata* .gnu.linkonce.r.*)
     . = ALIGN(8);
     *(.data)
     *(.data.*)
@@ -36,7 +41,8 @@ SECTIONS
     . = ALIGN(4096);
     _modules_end = .;
     
-  } : data
+  } : common
+
   _edata  =  .;
   PROVIDE (edata = .);
   . = ALIGN(4096);
@@ -46,7 +52,7 @@ SECTIONS
    *(.bss)
    *(COMMON)
    *(.bss_memmap)
-  } : data
+  } : common
   _end = . ;
   PROVIDE (end = .);
 
index 79c8218a1b219ed9986b7ca91f4fe30dd12762e6..4a138cb3de2c1e434b827b72ab3a8600c5ab9d7b 100644 (file)
 #define TRAP(H)  mov %psr, %l0; sethi %hi(H), %l4; jmp %l4+%lo(H); nop;
 #define TRAP_ENTRY(H) rd %psr, %l0; b H; rd %wim, %l3; nop;
-
 #define TRAP_ENTRY_INTERRUPT(int_level) \
         mov int_level, %l7; rd %psr, %l0; b _prom_leonbare_irq_entry; rd %wim, %l3;
+#define BAD_TRAP ta 0; nop; nop; nop;
 
 .data
-.space 8192
-.align(0x2000)
+.globl _leon_traphandlers
 .globl _stack
+
+.align(0x2000)
 _stack:
+.space 8192
 
 .text
 /*
  * Trap handler table -> must be aligned to page size
  * as specified by the SPARC v8 manual (p. 31).
  */
-.globl _leon_traphandlers
 .align(0x1000)
-.space(4096)
 _leon_traphandlers:
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  TRAP(sparc_window_overflow);
+  TRAP(sparc_window_underflow);
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
+  BAD_TRAP
 
-/*
- */
 .globl _start
 _start:
-    /* Things we should do here:
-        *  1) set up a trap handler table and load its address into %tbr
-        *  2) wait 3 instructions
-        */
 
-       /* set stack pointer */
-       sethi %hi(_stack), %sp
-       or %sp, %lo(_stack), %sp
+  rd %asr17, %g1
 
-       sethi %hi(_stack), %fp
-       or %fp, %lo(_stack), %fp
+  /*
+   * setup trap handler table
+   */
+  sethi %hi(_leon_traphandlers), %g2
+  wr %g2, %tbr
 
-       ba __main
-       nop
+  /* the TBR setup above comes into effect three instructions from now!
+   * Right now, we assume that no trap occurs in between.
+   */
 
-.text
-.globl main
-main:
-    ta 19
+  /* set stack pointer */
+  sethi %hi(_stack), %sp
+  or %sp, %lo(_stack), %sp
+
+  /*
+   * setup task with enough space for registers %l0-%l7 and %i0-%i7
+   */
+  sub %sp, 64, %sp
+
+  sethi %hi(_stack), %fp
+  or %fp, %lo(_stack), %fp
+
+  ba __main
+  nop
+
+  ta 0
+
+
+.globl sparc_window_overflow
+sparc_window_overflow:
+  mov %wim, %l3  /* need to determine new WIM */
+  mov %g1, %l7
+  srl %l3, 1, %g1
+
+  /*
+   * Find out if we are on LEON3 (PSR[24:27] == 3)
+   * or on LEON2. For LEON3, we can read the number of
+   * register windows from ASR17
+   */
+  mov %psr, %l4
+  srl %l4, 24, %l4
+  and %l4, 3, %l4
+  subcc %l4, 3, %g0
+  bne 1f
+  nop
+
+  /*
+   * It's a LEON3
+   */
+  mov %asr17, %l4
+
+  /* calculate new WIM */
+  and %l4, 0x1f, %l4
+  sll %l3, %l4, %l4
+  or %l4, %g1, %g1
+
+  /*
+   * The trick here is to move to a valid stack frame
+   * and store the register window contents there.
+   */
+  save
+     mov %g1, %wim
+     nop; nop; nop
+
+     std %l0, [%sp + 0];
+     std %l2, [%sp + 8];
+     std %l4, [%sp + 16];
+     std %l6, [%sp + 24];
+     std %i0, [%sp + 32];
+     std %i2, [%sp + 40];
+     std %i4, [%sp + 48];
+     std %i6, [%sp + 56];
+
+  restore
+  mov %l7, %g1
+  jmp %l1
+  rett %l2
+
+1: ta 0
+
+.globl sparc_window_underflow
+sparc_window_underflow:
+  mov %wim, %l3  /* need to determine new WIM */
+  sll %l3, 1, %l4
+
+  /* Determine LEON version */
+  mov %psr, %l5
+  srl %l5, 24, %l5
+  and %l4, 3, %l4
+  subcc %l4, 3, %g0
+  bne 1f
+  nop
+
+  mov %asr17, %l5
+  and %l5, 0x1f, %l5
+  srl %l3, %l5, %l5
+  or  %l5, %l4, %l5
+  mov %l5, %wim
+  nop; nop; nop
+
+  restore             ! Two restores to get into the
+  restore             ! window to restore
+  ldd   [%sp + 0], %l0;       ! Restore window from the stack
+  ldd   [%sp + 8], %l2;
+  ldd   [%sp + 16], %l4;
+  ldd   [%sp + 24], %l6;
+  ldd   [%sp + 32], %i0;
+  ldd   [%sp + 40], %i2;
+  ldd   [%sp + 48], %i4;
+  ldd   [%sp + 56], %i6;
+  save                ! Get back to the trap window.
+  save
+
+  jmp %l1
+  rett %l2
+
+1: ta 0
index 6598e46adb333e98ca8b18c7a542c74109a92719..f5cc04f8a6fa5e040b804845d6d301e63df30d2c 100644 (file)
@@ -14,7 +14,7 @@ DEFAULT_RELOC_arm   := 0x01000000
 DEFAULT_RELOC_x86   := 0x002d0000
 DEFAULT_RELOC_amd64 := 0x002d0000
 DEFAULT_RELOC_ppc32 := 0x002d0000
-DEFAULT_RELOC_sparc := 0x00100000
+DEFAULT_RELOC_sparc := 0x01000000
 RELOC_PHYS          := y
 LDFLAGS              = -Bstatic
 EXTRA_GENERAL_D_DEP  = .redo-change-tracker $(BID_RAM_BASE_DEP)
@@ -42,8 +42,8 @@ BOOTSTRAP_ELF_NAME           ?= bootstrap.elf
 MKIMAGE                      ?= mkimage
 BOOTSTRAP_UIMAGE_COMPRESSION ?= none
 
-ifeq ($(BUILD_ARCH),$(filter $(BUILD_ARCH),arm ppc32))
-  # ARM/PPC always uses single image mode
+ifeq ($(BUILD_ARCH),$(filter $(BUILD_ARCH),arm ppc32 sparc))
+  # ARM/PPC/SPARC always uses single image mode
   # when no entry is given we build the useless auto-build target
   ifeq ($(E)$(ENTRY),)
     BOOTSTRAP_ELF_NAME := bootstrap.auto-build-useless.elf
@@ -54,12 +54,6 @@ endif
 
 PRIVATE_INCDIR  = $(SRC_DIR) $(SRC_DIR)/ARCH-$(ARCH)
 
-# special include directories only needed for <l4/sys/kernel.h>
-PRIVATE_INCDIR_init_kip_v2.o      = $(OBJ_BASE)/include/$(ARCH)/l4f \
-                                    $(DROPS_STDDIR)/include/$(ARCH)/l4f
-PRIVATE_INCDIR_init_arm_kip.o     = $(OBJ_BASE)/include/$(ARCH)/l4f \
-                                    $(DROPS_STDDIR)/include/$(ARCH)/l4f
-
 TARGET         := $(BOOTSTRAP_ELF_NAME)
 TARGET_BIN      = $(BOOTSTRAP_ELF_NAME)
 MODE            = lib
@@ -77,32 +71,32 @@ PLATFORM_TYPE-sparc = $(SPARC_PLATFORM_TYPE)
 PLATFORM_TYPE       = $(PLATFORM_TYPE-$(ARCH))
 endif
 
-SUPPORT_CC_arm-sa1000     := support_sa1000.cc
-SUPPORT_CC_arm-pxa        := support_pxa.cc
-SUPPORT_CC_arm-integrator := support_integrator.cc
-SUPPORT_CC_arm-rv         := support_rv.cc
-SUPPORT_CC_arm-omap3evm   := support_omap.cc
-SUPPORT_CC_arm-beagleboard:= support_omap.cc
-SUPPORT_CC_arm-pandaboard := support_omap.cc
-SUPPORT_CC_arm-tegra2     := support_tegra2.cc
-SUPPORT_CC_arm-imx21      := support_imx.cc
-SUPPORT_CC_arm-imx35      := support_imx.cc
-SUPPORT_CC_arm-imx51      := support_imx.cc
-SUPPORT_CC_arm-om         := support_om.cc
-SUPPORT_CC_arm-kirkwood   := support_kirkwood.cc
+SUPPORT_CC_arm-sa1000     := platform/sa1000.cc
+SUPPORT_CC_arm-pxa        := platform/pxa.cc
+SUPPORT_CC_arm-integrator := platform/integrator.cc
+SUPPORT_CC_arm-rv         := platform/rv.cc
+SUPPORT_CC_arm-omap3evm   := platform/omap.cc
+SUPPORT_CC_arm-beagleboard:= platform/omap.cc
+SUPPORT_CC_arm-pandaboard := platform/omap.cc
+SUPPORT_CC_arm-tegra2     := platform/tegra2.cc
+SUPPORT_CC_arm-imx21      := platform/imx.cc
+SUPPORT_CC_arm-imx35      := platform/imx.cc
+SUPPORT_CC_arm-imx51      := platform/imx.cc
+SUPPORT_CC_arm-om         := platform/om.cc
+SUPPORT_CC_arm-kirkwood   := platform/kirkwood.cc
 DEFAULT_RELOC_arm-imx21   := 0x00200000  # because of blob
 
 ifneq ($(DEFAULT_RELOC_arm-$(PLATFORM_TYPE)),)
 DEFAULT_RELOC_arm         := $(DEFAULT_RELOC_arm-$(PLATFORM_TYPE))
 endif
 
-SUPPORT_CC_ppc32-mpc5200  := support_mpc5200.cc
+SUPPORT_CC_ppc32-mpc5200  := platform/mpc5200.cc
 
-SUPPORT_CC_x86-pc         := support_x86_pc.cc
+SUPPORT_CC_x86-pc         := platform/x86_pc.cc
 
-SUPPORT_CC_amd64-pc       := support_x86_pc.cc
+SUPPORT_CC_amd64-pc       := platform/x86_pc.cc
 
-SUPPORT_CC_sparc-leon3    := support_sparc_leon3.cc
+SUPPORT_CC_sparc-leon3    := platform/leon3.cc
 
 SRC_C          += exec.c module.c
 SRC_CC         += region.cc startup.cc init_kip_v2.cc init_kip_v4.cc \
@@ -225,7 +219,7 @@ all:: $(addprefix $(IMAGES_DIR)/,$(INSTALL_TARGET))
        $(VERBOSE)for f in $(filter bootstrap_$(ENTRY_FN).elf bootstrap.raw bootstrap.uimage, $(INSTALL_TARGET)); do \
          find . -name $$f -printf " %30f:  %s\n"; \
        done
-       $(if $(BOOTSTRAP_DO_RAW_IMAGE),$(VERBOSE)echo "  Start address: $(patsubst -Ttext=%,%,$(LDFLAGS_bootstrap.elf))")
+       $(if $(LDFLAGS_bootstrap.elf),$(VERBOSE)echo "  Start address: $(patsubst --defsym=__executable_start=%,%,$(LDFLAGS_bootstrap.elf))")
        $(VERBOSE)echo "  --> Build-Nr: $$(cat .build_nr)"
 
 # install images into easy to reach directory in build dir
index e98974a573b599d45faa6f9cb5f04443aefcc446..cb6b1f34e27f1734715230bb56056510191cbab6 100644 (file)
@@ -33,7 +33,7 @@ Platform_base *Platform_base::platform;
 
 static L4::Uart *stdio_uart;
 
-L4::Uart *uart() 
+L4::Uart *uart()
 { return stdio_uart; }
 
 void set_stdio_uart(L4::Uart *uart)
@@ -119,8 +119,8 @@ enum { _URC_FAILURE  = 9 };
 extern "C" int __aeabi_unwind_cpp_pr0(void) { return _URC_FAILURE; }
 extern "C" int __aeabi_unwind_cpp_pr1(void) { return _URC_FAILURE; }
 
-extern "C" void __main(int, const char **);
-void __main(int, const char **)
+extern "C" void __main();
+void __main()
 {
   extern int crt0_stack_low, crt0_stack_high;
   unsigned long r;
@@ -143,9 +143,8 @@ void __main(int, const char **)
 
 #ifdef ARCH_ppc32
 #include <l4/drivers/of.h>
-extern "C" void __main(unsigned long p1, unsigned long p2,
-                       unsigned long p3);
-void __main(unsigned long /*p1*/, unsigned long /*p2*/, unsigned long p3)
+extern "C" void __main(unsigned long p1, unsigned long p2, unsigned long p3);
+void __main(unsigned long, unsigned long, unsigned long p3)
 {
   extern int crt0_stack_low, crt0_stack_high;
   memset(_bss_start, 0, (char *)&crt0_stack_low - _bss_start);
@@ -174,15 +173,13 @@ void __main(unsigned long p1, unsigned long p2, unsigned long p3, unsigned long
 
 
 #if defined(ARCH_sparc)
-extern "C" void __main(unsigned long p1, unsigned long p2, unsigned long p3);
-void __main(unsigned long p1, unsigned long p2, unsigned long p3)
+
+extern "C" void __main();
+void __main()
 {
-       (void)p1;
-       (void)p2;
-       (void)p3;
-       ctor_init();
-       Platform_base::iterate_platforms();
-       // startup(0,0,0,0);
+  ctor_init();
+  Platform_base::iterate_platforms();
+  startup(0, 0, 0, 0);
 }
 #endif
 
diff --git a/l4/pkg/bootstrap/server/src/platform/imx.cc b/l4/pkg/bootstrap/server/src/platform/imx.cc
new file mode 100644 (file)
index 0000000..b7fc965
--- /dev/null
@@ -0,0 +1,47 @@
+/*!
+ * \file   support_imx.cc
+ * \brief  Support for the i.MX platform
+ *
+ * \date   2008-02-04
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_imx.h>
+
+namespace {
+class Platform_arm_imx : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+#ifdef PLATFORM_TYPE_imx21
+    static L4::Uart_imx21 _uart(0, 0);
+    _uart.startup(0x1000A000);
+#elif defined(PLATFORM_TYPE_imx35)
+    static L4::Uart_imx35 _uart(0, 0);
+    _uart.startup(0x43f90000); // UART-1
+    //_uart.startup(0x43f94000); // UART-2
+    //_uart.startup(0x5000c000); // UART-3
+#elif defined(PLATFORM_TYPE_imx51)
+    static L4::Uart_imx51 _uart(0, 0);
+    _uart.startup(0x73fbc000);
+#else
+#error Which platform type?
+#endif
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_imx);
diff --git a/l4/pkg/bootstrap/server/src/platform/integrator.cc b/l4/pkg/bootstrap/server/src/platform/integrator.cc
new file mode 100644 (file)
index 0000000..9b30a0e
--- /dev/null
@@ -0,0 +1,35 @@
+/*!
+ * \file   support_integrator.cc
+ * \brief  Support for the integrator platform
+ *
+ * \date   2008-01-02
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+class Platform_arm_int : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_pl011 _uart(1, 1);
+    _uart.startup(0x16000000);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_int);
diff --git a/l4/pkg/bootstrap/server/src/platform/kirkwood.cc b/l4/pkg/bootstrap/server/src/platform/kirkwood.cc
new file mode 100644 (file)
index 0000000..12e2fda
--- /dev/null
@@ -0,0 +1,44 @@
+/*!
+ * \file   support_kirkwood.cc
+ * \brief  Support for the kirkwood platform
+ *
+ * \date   2010-11
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pxa.h>
+
+namespace {
+class Platform_arm_kirkwood : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_pxa _uart(1, 1);
+    _uart.startup(0xf1012000); // uart0
+    //_uart.startup(0xf1012100); // uart1
+    _uart.change_mode(0x3, 8500); // TCLK=200000000, Divisor: 108=TCLK/115200/16
+    set_stdio_uart(&_uart);
+
+
+    // SPI init, as there's an interrupt pending when coming from u-boot on
+    // the dockstar, so make it go away
+    *(unsigned *)0xf1010600 = 0; // disable
+    *(unsigned *)0xf1010614 = 0; // mask interrupt
+    *(unsigned *)0xf1010610 = 1; // clear interrupt
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_kirkwood);
diff --git a/l4/pkg/bootstrap/server/src/platform/leon3.cc b/l4/pkg/bootstrap/server/src/platform/leon3.cc
new file mode 100644 (file)
index 0000000..6a9d999
--- /dev/null
@@ -0,0 +1,36 @@
+/**
+ * \file   support_sparc_leon3.cc
+ * \brief  Support for the Sparc LEON3 platform
+ *
+ * \date   2010
+ * \author Björn Döbel <doebel@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include <l4/drivers/uart_leon3.h>
+
+#include "support.h"
+
+namespace {
+class Platform_leon3 : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_leon3 _uart(1,1);
+    _uart.startup(0x80000100);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_leon3);
diff --git a/l4/pkg/bootstrap/server/src/platform/mpc5200.cc b/l4/pkg/bootstrap/server/src/platform/mpc5200.cc
new file mode 100644 (file)
index 0000000..3948c0f
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * \file
+ * \brief  Support for the MPC52000
+ *
+ * \date   2009-02-16
+ * \author Sebastian Sumpf <sumpf@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_of.h>
+
+
+namespace {
+class Platform_ppc_mpc52000 : public Platform_base
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_of _uart;
+    _uart.startup(0);
+    set_stdio_uart(&_uart);
+  }
+  void setup_memory_map(l4util_mb_info_t *,
+                        Region_list *, Region_list *)
+  {
+    // still done in startup.cc
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_ppc_mpc52000);
diff --git a/l4/pkg/bootstrap/server/src/platform/om.cc b/l4/pkg/bootstrap/server/src/platform/om.cc
new file mode 100644 (file)
index 0000000..ca6e35e
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * \file   support_om.cc
+ * \brief  Support for the OpenMoko platform
+ *
+ * \date   2008
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+
+#include "support.h"
+
+#include <l4/drivers/uart_s3c2410.h>
+#include <l4/drivers/uart_dummy.h>
+
+#define UART_TYPE Uart_s3c2410
+//#define UART_TYPE Uart_dummy
+
+namespace {
+class Platform_arm_om : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::UART_TYPE _uart(1,1);
+    _uart.startup(0x50000000);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_om);
diff --git a/l4/pkg/bootstrap/server/src/platform/omap.cc b/l4/pkg/bootstrap/server/src/platform/omap.cc
new file mode 100644 (file)
index 0000000..e6272ad
--- /dev/null
@@ -0,0 +1,43 @@
+/*!
+ * \file   support_beagleboard.cc
+ * \brief  Support for the Beagleboard
+ *
+ * \date   2009-08
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_omap35x.h>
+
+namespace {
+class Platform_arm_omap : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_omap35x _uart(1, 1);
+#ifdef PLATFORM_TYPE_beagleboard
+    _uart.startup(0x49020000);
+#elif defined(PLATFORM_TYPE_omap3evm)
+    _uart.startup(0x4806a000);
+#elif defined(PLATFORM_TYPE_pandaboard)
+    _uart.startup(0x48020000);
+#else
+#error Unknown platform
+#endif
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_omap);
diff --git a/l4/pkg/bootstrap/server/src/platform/pxa.cc b/l4/pkg/bootstrap/server/src/platform/pxa.cc
new file mode 100644 (file)
index 0000000..451cca8
--- /dev/null
@@ -0,0 +1,35 @@
+/*!
+ * \file   support_pxa.cc
+ * \brief  Support for the PXA platform
+ *
+ * \date   2008-01-04
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pxa.h>
+
+namespace {
+class Platform_arm_pxa : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_pxa _uart(1,1);
+    _uart.startup(0x40100000);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_pxa);
diff --git a/l4/pkg/bootstrap/server/src/platform/rv.cc b/l4/pkg/bootstrap/server/src/platform/rv.cc
new file mode 100644 (file)
index 0000000..dc1b857
--- /dev/null
@@ -0,0 +1,35 @@
+/*!
+ * \file   support_rv.cc
+ * \brief  Support for the rv platform
+ *
+ * \date   2008-01-02
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+
+#include <l4/drivers/uart_pl011.h>
+
+namespace {
+class Platform_arm_rv : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+  void init()
+  {
+    static L4::Uart_pl011 _uart(36,36);
+    _uart.startup(0x10009000);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_rv);
diff --git a/l4/pkg/bootstrap/server/src/platform/sa1000.cc b/l4/pkg/bootstrap/server/src/platform/sa1000.cc
new file mode 100644 (file)
index 0000000..518f21e
--- /dev/null
@@ -0,0 +1,36 @@
+/*!
+ * \file   support_sa1000.cc
+ * \brief  Support for SA1000 platform
+ *
+ * \date   2008-01-02
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_sa1000.h>
+
+namespace {
+class Platform_arm_sa1000 : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_sa1000 _uart(1,1);
+    _uart.startup(0x80010000);
+    //_uart.startup(0x80050000);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_sa1000);
diff --git a/l4/pkg/bootstrap/server/src/platform/tegra2.cc b/l4/pkg/bootstrap/server/src/platform/tegra2.cc
new file mode 100644 (file)
index 0000000..e1a7672
--- /dev/null
@@ -0,0 +1,87 @@
+/*!
+ * \file
+ * \brief  Support for Tegra 2 platforms
+ *
+ * \date   2010-05
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2010 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+/* Init-code from http://android.git.kernel.org/?p=kernel/tegra.git */
+
+#include "support.h"
+#include <l4/drivers/uart_pxa.h>
+
+namespace {
+class Platform_arm_tegra2 : public Platform_base
+{
+private:
+  void some_delay(int d) const
+    {
+      for (int i = 0; i <  d; i++)
+        asm volatile("":::"memory");
+    }
+
+public:
+  bool probe() { return true; }
+
+  void init()
+  {
+    volatile unsigned long *addr;
+
+    addr = (volatile unsigned long *)0x600060a0;
+    *addr = 0x5011b00c;
+
+    /* PLLP_OUTA_0 */
+    addr = (volatile unsigned long *)0x600060a4;
+    *addr = 0x10031c03;
+
+    /* PLLP_OUTB_0 */
+    addr = (volatile unsigned long *)0x600060a8;
+    *addr = 0x06030a03;
+
+    /* PLLP_MISC_0 */
+    addr = (volatile unsigned long *)0x600060ac;
+    *addr = 0x00000800;
+
+    some_delay(1000000);
+
+    /* UARTD clock source is PLLP_OUT0 */
+    addr = (volatile unsigned long *)0x600061c0;
+    *addr = 0;
+
+    /* Enable clock to UARTD */
+    addr = (volatile unsigned long *)0x60006018;
+    *addr |= 2;
+    some_delay(5000);
+
+    /* Deassert reset to UARTD */
+    addr = (volatile unsigned long *)0x6000600c;
+    *addr &= ~2;
+
+    some_delay(5000);
+
+    static L4::Uart_pxa _uart(1, 1);
+    _uart.startup(0x70006300);
+    _uart.change_mode(3, 7876);
+    set_stdio_uart(&_uart);
+  }
+
+  void setup_memory_map(l4util_mb_info_t *,
+                        Region_list *ram, Region_list *)
+  {
+    ram->add(Region::n(0x0,        448 << 20, ".ram", Region::Ram));
+    ram->add(Region::n(512 << 20, 1024 << 20, ".ram", Region::Ram));
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_tegra2);
diff --git a/l4/pkg/bootstrap/server/src/platform/x86_pc.cc b/l4/pkg/bootstrap/server/src/platform/x86_pc.cc
new file mode 100644 (file)
index 0000000..0a58ed7
--- /dev/null
@@ -0,0 +1,522 @@
+/*!
+ * \file   support_x86.cc
+ * \brief  Support for the x86 platform
+ *
+ * \date   2008-01-02
+ * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2008-2009 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+
+namespace L4
+{
+  class Uart_x86 : public Uart
+  {
+  private:
+    unsigned long _base;
+
+    inline unsigned long rd(unsigned long reg) const;
+    inline void wr(unsigned long reg, unsigned long val) const;
+
+  public:
+    Uart_x86(int rx_irq, int tx_irq)
+      : Uart(rx_irq, tx_irq), _base(~0UL) {}
+    bool startup(unsigned long base);
+    void shutdown();
+    bool enable_rx_irq(bool enable = true);
+    bool enable_tx_irq(bool enable = true);
+    bool change_mode(Transfer_mode m, Baud_rate r);
+    int get_char(bool blocking = true) const;
+    int char_avail() const;
+    inline void out_char(char c) const;
+    int write(char const *s, unsigned long count) const;
+  };
+};
+
+
+#include <string.h>
+#include "base_critical.h"
+#include "ARCH-x86/serial.h"
+#include <l4/util/cpu.h>
+#include <l4/util/port_io.h>
+#include <assert.h>
+
+/** VGA console output */
+
+static void
+vga_init()
+{
+  /* Reset any scrolling */
+  l4util_out32(0xc, 0x3d4);
+  l4util_out32(0, 0x3d5);
+  l4util_out32(0xd, 0x3d4);
+  l4util_out32(0, 0x3d5);
+}
+
+static void
+vga_putchar(unsigned char c)
+{
+  static int ofs = -1, esc, esc_val, attr = 0x07;
+  unsigned char *vidbase = (unsigned char*)0xb8000;
+
+  base_critical_enter();
+
+  if (ofs < 0)
+    {
+      /* Called for the first time - initialize.  */
+      ofs = 80*2*24;
+      vga_putchar('\n');
+    }
+
+  switch (esc)
+    {
+    case 1:
+      if (c == '[')
+       {
+         esc++;
+         goto done;
+       }
+      esc = 0;
+      break;
+
+    case 2:
+      if (c >= '0' && c <= '9')
+       {
+         esc_val = 10*esc_val + c - '0';
+         goto done;
+       }
+      if (c == 'm')
+       {
+         attr = esc_val ? 0x0f : 0x07;
+         goto done;
+       }
+      esc = 0;
+      break;
+    }
+
+  switch (c)
+    {
+    case '\n':
+      memmove(vidbase, vidbase+80*2, 80*2*24);
+      memset(vidbase+80*2*24, 0, 80*2);
+      /* fall through... */
+    case '\r':
+      ofs = 0;
+      break;
+
+    case '\t':
+      ofs = (ofs + 8) & ~7;
+      break;
+
+    case '\033':
+      esc = 1;
+      esc_val = 0;
+      break;
+
+    default:
+      /* Wrap if we reach the end of a line.  */
+      if (ofs >= 80)
+       vga_putchar('\n');
+
+      /* Stuff the character into the video buffer. */
+       {
+         volatile unsigned char *p = vidbase + 80*2*24 + ofs*2;
+         p[0] = c;
+         p[1] = attr;
+         ofs++;
+       }
+      break;
+    }
+
+done:
+  base_critical_leave();
+}
+
+/** Poor man's getchar, only returns raw scan code. We don't need to know
+ * _which_ key was pressed, we only want to know _if_ a key was pressed. */
+static int
+raw_keyboard_getscancode(void)
+{
+  unsigned status, scan_code;
+
+  base_critical_enter();
+
+  l4util_cpu_pause();
+
+  /* Wait until a scan code is ready and read it. */
+  status = l4util_in8(0x64);
+  if ((status & 0x01) == 0)
+    {
+      base_critical_leave();
+      return -1;
+    }
+  scan_code = l4util_in8(0x60);
+
+  /* Drop mouse events */
+  if ((status & 0x20) != 0)
+    {
+      base_critical_leave();
+      return -1;
+    }
+
+  base_critical_leave();
+  return scan_code;
+}
+
+namespace L4
+{
+  bool Uart_x86::startup(unsigned long /*base*/)
+  // real uart init will be made by startup.cc if told by cmdline
+  { vga_init(); return true; }
+
+  void Uart_x86::shutdown() {}
+  bool Uart_x86::enable_rx_irq(bool) { return true; }
+  bool Uart_x86::enable_tx_irq(bool) { return false; }
+  bool Uart_x86::change_mode(Transfer_mode, Baud_rate) { return false; }
+
+  int Uart_x86::get_char(bool blocking) const
+  {
+    int c;
+    do {
+      c = com_cons_try_getchar();
+      if (c == -1)
+        c = raw_keyboard_getscancode();
+      l4util_cpu_pause();
+    } while (c == -1 && blocking);
+
+    return c;
+  }
+
+  int Uart_x86::char_avail() const
+  {
+    return com_cons_char_avail();
+  }
+
+  void Uart_x86::out_char(char c) const
+  {
+    vga_putchar(c);      // vga out
+    com_cons_putchar(c); // serial out
+  }
+
+  int Uart_x86::write(char const *s, unsigned long count) const
+  {
+    unsigned long c = count;
+    while (c)
+      {
+        if (*s == 10)
+          out_char(13);
+        out_char(*s++);
+        --c;
+      }
+    return count;
+  }
+};
+
+
+static inline l4_uint32_t
+pci_conf_addr(l4_uint32_t bus, l4_uint32_t dev, l4_uint32_t fn, l4_uint32_t reg)
+{ return 0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3); }
+
+static l4_uint32_t pci_read(unsigned char bus, l4_uint32_t dev,
+                            l4_uint32_t fn, l4_uint32_t reg,
+                            unsigned char width)
+{
+  l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
+
+  switch (width)
+    {
+    case 8:  return l4util_in8(0xcfc + (reg & 3));
+    case 16: return l4util_in16((0xcfc + (reg & 3)) & ~1UL);
+    case 32: return l4util_in32(0xcfc);
+    }
+  return 0;
+}
+
+static void pci_write(unsigned char bus, l4_uint32_t dev,
+                      l4_uint32_t fn, l4_uint32_t reg,
+                      l4_uint32_t val, unsigned char width)
+{
+  l4util_out32(pci_conf_addr(bus, dev, fn, reg), 0xcf8);
+
+  switch (width)
+    {
+    case 8:  l4util_out8(val, 0xcfc + (reg & 3)); break;
+    case 16: l4util_out16(val, (0xcfc + (reg & 3)) & ~1UL); break;
+    case 32: l4util_out32(val, 0xcfc); break;
+    }
+}
+
+static void pci_enable_io(unsigned char bus, l4_uint32_t dev,
+                          l4_uint32_t fn)
+{
+  unsigned cmd = pci_read(bus, dev, fn, 4, 16);
+  pci_write(bus, dev, fn, 4, cmd | 1, 16);
+}
+
+#include <stdio.h>
+
+namespace {
+
+struct Resource
+{
+  enum Type { NO_BAR, IO_BAR, MEM_BAR };
+  Type type;
+  unsigned long base;
+  unsigned long len;
+  Resource() : type(NO_BAR) {}
+};
+
+enum { NUM_BARS = 6 };
+
+struct Serial_board
+{
+  int num_ports;
+  int first_bar;
+  bool port_per_bar;
+  Resource bars[NUM_BARS];
+
+  unsigned long get_port(int idx)
+  {
+    if (idx >= num_ports)
+      return 0;
+
+    if (port_per_bar)
+      return bars[first_bar + idx].base;
+
+    return bars[first_bar].base + 8 * idx;
+  }
+};
+
+
+}
+
+static
+int pci_handle_serial_dev(unsigned char bus, l4_uint32_t dev,
+                          l4_uint32_t subdev, bool scan_only,
+                          Serial_board *board)
+{
+#if 0
+  bool dev_enabled = false;
+#endif
+
+
+  // read bars
+  int num_iobars = 0;
+  int num_membars = 0;
+  int first_port = -1;
+  for (int bar = 0; bar < NUM_BARS; ++bar)
+    {
+      int a = 0x10 + bar * 4;
+
+      unsigned v = pci_read(bus, dev, subdev, a, 32);
+      pci_write(bus, dev, subdev, a, ~0U, 32);
+      unsigned x = pci_read(bus, dev, subdev, a, 32);
+      pci_write(bus, dev, subdev, a, v, 32);
+
+      if (!v)
+        continue;
+
+      int s;
+      for (s = 2; s < 32; ++s)
+        if ((x >> s) & 1)
+          break;
+
+      board->bars[bar].base = v & ~3UL;
+      board->bars[bar].len = 1 << s;
+      board->bars[bar].type = (v & 1) ? Resource::IO_BAR : Resource::MEM_BAR;
+
+      if (scan_only)
+       printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
+
+      switch (board->bars[bar].type)
+       {
+       case Resource::IO_BAR:
+         ++num_iobars;
+         if (first_port == -1)
+           first_port = bar;
+         break;
+       case Resource::MEM_BAR:
+         ++num_membars;
+         break;
+       default:
+         break;
+       }
+    }
+
+  if (num_membars <= 1 && num_iobars == 1)
+    {
+      board->first_bar = first_port;
+      board->num_ports = board->bars[first_port].len / 8;
+      board->port_per_bar = false;
+      pci_enable_io(bus, dev, subdev);
+      return 1;
+    }
+
+
+  board->num_ports = 0;
+  board->first_bar = -1;
+
+  for (int bar = 0; bar < NUM_BARS; ++bar)
+    {
+      if (board->bars[bar].type == Resource::IO_BAR && board->bars[bar].len == 8
+         && (board->first_bar == -1
+             || (board->first_bar + board->num_ports) == bar))
+       {
+         ++board->num_ports;
+         if (board->first_bar == -1)
+           board->first_bar = bar;
+       }
+    }
+
+  board->port_per_bar = true;
+  return board->num_ports;
+
+#if 0
+
+      // for now we only take IO-BARs of size 8
+      if (v & 1)
+        {
+
+          if (!scan_only && !dev_enabled)
+            {
+              pci_enable_io(bus, dev, subdev);
+              dev_enabled = true;
+            }
+
+          if (scan_only)
+            printf("BAR%d: %04x (sz=%d)\n", bar, v & ~3, 1 << s);
+
+          if (s == 3)
+            {
+              if (scan_only)
+                printf("   Potential serial port\n");
+              else
+                return v & ~3;
+            }
+        }
+      else
+        if (scan_only)
+          printf("BAR%d: %08x (sz=%d)\n", bar, v & ~0xf, 1 << s);
+    }
+  return 0;
+#endif
+}
+
+static unsigned long _search_pci_serial_devs(Serial_board *board, bool scan_only)
+{
+  l4_umword_t bus, buses, dev;
+
+  for (bus=0, buses=20; bus<buses; bus++)
+    {
+      for (dev = 0; dev < 32; dev++)
+        {
+          unsigned char hdr_type = pci_read(bus, dev, 0, 0xe, 8);
+          l4_umword_t subdevs = (hdr_type & 0x80) ? 8 : 1;
+
+          for (l4_umword_t subdev = 0; subdev < subdevs; subdev++)
+            {
+              unsigned vendor = pci_read(bus, dev, subdev, 0, 16);
+              unsigned device = pci_read(bus, dev, subdev, 2, 16);
+
+              if ((vendor == 0xffff && device == 0xffff) ||
+                  (device == 0x0000 && device == 0x0000))
+                break;
+
+              unsigned classcode = pci_read(bus, dev, subdev, 0x0b, 8);
+              unsigned subclass  = pci_read(bus, dev, subdev, 0x0a, 8);
+
+              if (classcode == 0x06 && subclass == 0x04)
+                buses++;
+
+              unsigned prog = pci_read(bus, dev, subdev, 9, 8);
+
+              if (scan_only)
+                printf("%02lx:%02lx.%1lx Class %02x.%02x Prog %02x: %04x:%04x\n",
+                       bus, dev, subdev, classcode, subclass, prog, vendor, device);
+
+              if (classcode == 7 && subclass == 0)
+                if (unsigned long port = pci_handle_serial_dev(bus, dev,
+                                                               subdev, scan_only, board))
+                  return port;
+            }
+        }
+    }
+  return 0;
+}
+
+unsigned long search_pci_serial_devs(int port_idx, bool scan_only)
+{
+  Serial_board board;
+  if (!_search_pci_serial_devs(&board, scan_only))
+    return 0;
+
+  return board.get_port(port_idx);
+}
+
+namespace {
+
+class Platform_x86 : public Platform_base
+{
+public:
+  bool probe() { return true; }
+  void init()
+  {
+    // this is just a wrapper around serial.c
+    // if you think this could be done better you're right...
+    static L4::Uart_x86 _uart(1,1);
+    _uart.startup(0);
+    set_stdio_uart(&_uart);
+  }
+
+  void setup_memory_map(l4util_mb_info_t *mbi,
+                        Region_list *ram, Region_list *regions)
+  {
+    if (!(mbi->flags & L4UTIL_MB_MEM_MAP))
+      {
+        assert(mbi->flags & L4UTIL_MB_MEMORY);
+        ram->add(Region::n(0, (mbi->mem_upper + 1024) << 10, ".ram",
+                  Region::Ram));
+      }
+    else
+      {
+        l4util_mb_addr_range_t *mmap;
+        l4util_mb_for_each_mmap_entry(mmap, mbi)
+          {
+            unsigned long long start = (unsigned long long)mmap->addr;
+            unsigned long long end = (unsigned long long)mmap->addr + mmap->size;
+
+            switch (mmap->type)
+              {
+              case 1:
+                ram->add(Region::n(start, end, ".ram", Region::Ram));
+                break;
+              case 2:
+              case 3:
+              case 4:
+                regions->add(Region::n(start, end, ".BIOS", Region::Arch, mmap->type));
+                break;
+              case 5:
+                regions->add(Region::n(start, end, ".BIOS", Region::No_mem));
+                break;
+              default:
+                break;
+              }
+          }
+      }
+
+    regions->add(Region::n(0, 0x1000, ".BIOS", Region::Arch, 0));
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_x86);
+
index 40cbd6a343effd6f213a42566d57d57584db82b9..c12ffb04909a9987c2c1b1cd9711fa80ddc5358a 100644 (file)
@@ -978,17 +978,18 @@ init_pc_serial(l4util_mb_info_t *mbi)
       if (comport == -1)
         comport = 1;
 
-      com_cons_init(comport, comirq, &kuart, &kuart_flags);
+      if (com_cons_init(comport, comirq, &kuart, &kuart_flags))
+        printf("UART init failed\n");
     }
 #else
   (void)mbi;
 #endif
 }
 
-#ifdef ARCH_arm
+#if defined(ARCH_arm) || defined(ARCH_ppc32) || defined(ARCH_sparc)
 #ifndef IMAGE_MODE
 // check that our is_precious_ram function can work ok
-#error For ARM, IMAGE_MODE must always be enabled
+#error For ARM/PPC/SPARC, IMAGE_MODE must always be enabled
 #endif
 
 /* Occupied RAM at the point we are scannig it */
index f78299c0c56bff383b332f2c3cecce441ada2585..d07db7cd41c752959d901b5db7cf4209e78f750d 100644 (file)
@@ -1,5 +1,5 @@
 PKGDIR = ../../..
 L4DIR  ?= $(PKGDIR)/../..
-EXTRA_TARGET := exceptions string
+EXTRA_TARGET := exceptions string std_exc_io
 
 include $(L4DIR)/mk/include.mk
diff --git a/l4/pkg/cxx/lib/base/include/std_exc_io b/l4/pkg/cxx/lib/base/include/std_exc_io
new file mode 100644 (file)
index 0000000..4e9d2d5
--- /dev/null
@@ -0,0 +1,54 @@
+// vi:ft=cpp
+/**
+ * \file
+ * \brief Base exceptions std stream operator
+ * \ingroup l4cxx_exceptions
+ */
+/*
+ * (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *          Alexander Warg <warg@os.inf.tu-dresden.de>
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+#pragma once
+
+#include <l4/cxx/exceptions>
+#include <iostream>
+
+inline
+std::ostream &
+operator << (std::ostream &o, L4::Base_exception const &e)
+{
+  o << "Exception: " << e.str() << ", backtrace ...\n";
+  for (int i = 0; i < e.frame_count(); ++i)
+    o << (void *)(e.pc_array()[i]) << '\n';
+
+  return o;
+}
+
+inline
+std::ostream &
+operator << (std::ostream &o, L4::Runtime_error const &e)
+{
+  o << "Exception: " << e.str() << ": ";
+  if (e.extra_str())
+    o << e.extra_str() << ": ";
+  o << "backtrace ...\n";
+  for (int i = 0; i < e.frame_count(); ++i)
+    o << (void *)(e.pc_array()[i]) << '\n';
+
+  return o;
+}
index 11cbe40a61952876097564eb0d47cf40a7a3b425..4b6d5f7c8f5973259bc095f2d01826e9b65ad3dd 100644 (file)
@@ -835,7 +835,7 @@ T read(Istream &s) { T t; s >> t; return t; }
  * \endlink.
  *
  * There exist some special wrapper classes to insert arrays (see
- * Ipc_buf_cp_out) and indirect strings (see Msg_out_buffer and
+ * Ipc::Buf_cp_out) and indirect strings (see Msg_out_buffer and
  * Msg_io_buffer). */
 class Ostream
 {
@@ -1282,7 +1282,7 @@ L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, l4_msgtag_t &v)
  * returns a pointer into the message buffer itself. This means that the
  * data is only valid as long as there is no new data inserted into the stream.
  *
- * See Ipc_buf_in, Ipc_bufcp_in, and Ipc_buf_cp_out.
+ * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
  *
  * \param s The stream to extract from.
  * \param v Output: pointer to the extracted array (ipc_buf_in()).
@@ -1329,10 +1329,10 @@ L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
  *
  * This operator does a copy out of the data into the given buffer.
  *
- * See Ipc_buf_in, Ipc_bufcp_in, and Ipc_buf_cp_out.
+ * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
  *
  * \param s The stream to extract from.
- * \param v buffer description to copy the array to (ipc_buf_cp_out()).
+ * \param v buffer description to copy the array to (Ipc::Buf_cp_out()).
  * \return the stream \a s.
  */
 template< typename T >
@@ -1399,7 +1399,7 @@ L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, l4_msgtag_t const &v)
  * \ingroup ipc_stream
  *
  * \param s The stream to insert the array \a v.
- * \param v The array to insert (see ipc_buf_cp_out()).
+ * \param v The array to insert (see Ipc::Buf_cp_out()).
  * \return the stream \a s.
  */
 template< typename T >
@@ -1437,33 +1437,54 @@ L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char const *v)
 #ifdef L4_CXX_IPC_BACKWARD_COMPAT
 namespace L4 {
 
+#if 0
 template< typename T > class Ipc_buf_cp_out : public Ipc::Buf_cp_out<T> {};
 template< typename T > class Ipc_buf_cp_in : public Ipc::Buf_cp_in<T> {};
 template< typename T > class Ipc_buf_in : public Ipc::Buf_in<T> {};
 template< typename T > class Msg_ptr : public Ipc::Msg_ptr<T> {};
+#endif
+
+template< typename T >
+Ipc::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
+  L4_DEPRECATED("Use L4::Ipc::Buf_cp_out<type>() now");
 
 template< typename T >
 Ipc::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
 { return Ipc::Buf_cp_out<T>(v,size); }
 
+
+template< typename T >
+Ipc::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
+  L4_DEPRECATED("Use L4::Ipc::Buf_cp_in<type>() now");
+
 template< typename T >
 Ipc::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
 { return Ipc::Buf_cp_in<T>(v,size); }
 
+
+template< typename T >
+Ipc::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
+  L4_DEPRECATED("Use L4::Ipc::Buf_in<type>() now");
+
 template< typename T >
 Ipc::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
 { return Ipc::Buf_in<T>(v, size); }
 
+
+template< typename T >
+Ipc::Msg_ptr<T> msg_ptr(T *&p)
+  L4_DEPRECATED("Use L4::Ipc::Msg_ptr<type>() now");
+
 template< typename T >
 Ipc::Msg_ptr<T> msg_ptr(T *&p)
 { return Ipc::Msg_ptr<T>(p); }
 
-typedef Ipc::Istream Ipc_istream;
-typedef Ipc::Ostream Ipc_ostream;
-typedef Ipc::Iostream Ipc_iostream;
-typedef Ipc::Snd_fpage Snd_fpage;
-typedef Ipc::Rcv_fpage Rcv_fpage;
-typedef Ipc::Small_buf Small_buf;
+typedef Ipc::Istream Ipc_istream L4_DEPRECATED("Use L4::Ipc::Istream now");
+typedef Ipc::Ostream Ipc_ostream L4_DEPRECATED("Use L4::Ipc::Ostream now");;
+typedef Ipc::Iostream Ipc_iostream L4_DEPRECATED("Use L4::Ipc::Iostream now");;
+typedef Ipc::Snd_fpage Snd_fpage L4_DEPRECATED("Use L4::Ipc::Snd_fpage now");;
+typedef Ipc::Rcv_fpage Rcv_fpage L4_DEPRECATED("Use L4::Ipc::Rcv_fpage now");;
+typedef Ipc::Small_buf Small_buf L4_DEPRECATED("Use L4::Ipc::Small_buf now");;
 
 }
 #endif
index eadec40ec88d9b6b664d3105f150140c0639d656..212332f7d7562a4112dad1afab8ec1e7a723d4c3 100644 (file)
@@ -233,7 +233,7 @@ Avl_tree<Node, Get_key, Compare>::insert(Node *new_node)
   // search insertion point
   for (N *p; (p = *t);)
     {
-      Dir b = dir(new_key, p);
+      Dir b = this->dir(new_key, p);
       if (b == Dir::N)
        return pair(static_cast<Node*>(p), false);
 
@@ -250,7 +250,7 @@ Avl_tree<Node, Get_key, Compare>::insert(Node *new_node)
   A *a = static_cast<A*>(n);
   if (!a->balanced())
     {
-      A::Bal b(greater(new_key, n));
+      A::Bal b(this->greater(new_key, n));
       if (a->balance() != b)
        {
          // ok we got in balance the shorter subtree go higher
@@ -258,7 +258,7 @@ Avl_tree<Node, Get_key, Compare>::insert(Node *new_node)
          // propagate the new balance down to the new node
          n = N::next(n, b);
        }
-      else if (b == Bal(greater(new_key, N::next(n, b))))
+      else if (b == Bal(this->greater(new_key, N::next(n, b))))
        {
          // left-left or right-right case -> single rotation
          A::rotate(s, b);
@@ -270,12 +270,12 @@ Avl_tree<Node, Get_key, Compare>::insert(Node *new_node)
        {
          // need a double rotation
          n = N::next(N::next(n, b), !b);
-         n = A::rotate2(s, b, n == new_node ? Bal::N : Bal(greater(new_key, n)));
+         n = A::rotate2(s, b, n == new_node ? Bal::N : Bal(this->greater(new_key, n)));
        }
     }
 
   for (A::Bal b; n && n != new_node; static_cast<A*>(n)->balance(b), n = N::next(n, b))
-    b = Bal(greater(new_key, n));
+    b = Bal(this->greater(new_key, n));
 
   return pair(new_node, true);
 }
@@ -298,8 +298,8 @@ Node *Avl_tree<Node, Get_key, Compare>::remove(Key_param_type key)
   // find target node and rebalancing entry
   for (N *n; (n = *q); q = N::next_p(n, dir))
     {
-      dir = Dir(greater(key, n));
-      if (dir == Dir::L && !greater(k(n), key))
+      dir = Dir(this->greater(key, n));
+      if (dir == Dir::L && !this->greater(k(n), key))
        /* found node */
        t = q;
 
@@ -319,7 +319,7 @@ Node *Avl_tree<Node, Get_key, Compare>::remove(Key_param_type key)
 
   for (N *n; (n = *s); s = N::next_p(n, dir))
     {
-      dir = Dir(greater(key, n));
+      dir = Dir(this->greater(key, n));
 
       if (!N::next(n, dir))
        break;
index 2e21e571a8a9d763c2344981a794ec5ec8a44679..6eaa9793e346055cdacb14501a8a215155cd5686 100644 (file)
@@ -4,7 +4,7 @@
 #include <l4/input/libinput.h>
 
 /** event callback function */
-typedef void (*linux_ev_callback)(struct l4input *);
+typedef L4_CV void (*linux_ev_callback)(struct l4input *);
 
 extern linux_ev_callback l4dde26_ev_callback;
 
index 400b87a9a7906180c3f77a68726359786ae0f268..0c18b0a141477411fdfd28bc6208898776ffadcd 100644 (file)
@@ -6,22 +6,22 @@
 
 extern int dde_evdev_open(int i);
 
-int l4input_pcspkr(int tone)
+L4_CV int l4input_pcspkr(int tone)
 {
   return 0;
 }
 
-int l4input_ispending(void)
+L4_CV int l4input_ispending(void)
 {
   return 0;
 }
 
-int l4input_flush(void *buffer, int count)
+L4_CV int l4input_flush(void *buffer, int count)
 {
   return 0;
 }
 
-int l4input_init(int mode, linux_ev_callback cb)
+L4_CV int l4input_init(int mode, linux_ev_callback cb)
 {
        l4dde26_register_ev_callback(cb);
 
index 032e5ddbb5eb5c61a7ab921c0a92615d3d08e747..246a486042b3127a8d9d3bbb75040e1dc029e8be 100644 (file)
@@ -270,7 +270,7 @@ static inline struct ddekit_slab *ddekit_slab_from_l4slab(l4slab_cache_t *s)
 /**
  * Grow slab cache
  */
-EXTERN_C void *_slab_grow(l4slab_cache_t *cache, void **data)
+EXTERN_C L4_CV void *_slab_grow(l4slab_cache_t *cache, void **data)
 {
        /* the page(s) to be returned */
        void *res = NULL;
@@ -315,7 +315,7 @@ EXTERN_C void *_slab_grow(l4slab_cache_t *cache, void **data)
 /**
  * Shrink slab cache
  */
-EXTERN_C void _slab_shrink(l4slab_cache_t *cache, void *page, void *data)
+EXTERN_C L4_CV void _slab_shrink(l4slab_cache_t *cache, void *page, void *data)
 {
 #if 0
        ddekit_printf("%s: cache %p, page %p, data %p\n",
index 94387fb50e1b09d1545c75d16106a0e8a19d5a07..9c79d9f4032b61496555897b8f02d1f8db80432b 100644 (file)
@@ -55,8 +55,8 @@ char *dopelib_callback_to_bindarg(void (*callback)(dope_event *,void *),
 
 
 /*** INTERFACE: BIND AN EVENT TO A DOpE WIDGET ***/
-void dope_bind(const char *var, const char *event_type,
-               void (*callback)(dope_event *,void *), void *arg)
+L4_CV void dope_bind(const char *var, const char *event_type,
+                     void (*callback)(dope_event *,void *), void *arg)
 {
   char cmdbuf[256];
   char bindbuf[64];
@@ -73,7 +73,7 @@ void dope_bind(const char *var, const char *event_type,
 
 
 /*** INTERFACE: BIND AN EVENT TO A DOpE WIDGET SPECIFIED AS FORMAT STRING ***/
-void dope_bindf(const char *varfmt, const char *event_type,
+L4_CV void dope_bindf(const char *varfmt, const char *event_type,
                 void (*callback)(dope_event *,void *), void *arg,...)
 {
   char varstr[512];
@@ -87,7 +87,7 @@ void dope_bindf(const char *varfmt, const char *event_type,
   dope_bind(varstr, event_type, callback, arg);
 }
 
-char *dope_get_bindarg(l4re_event_t *ev)
+L4_CV char *dope_get_bindarg(l4re_event_t *ev)
 {
   if (!ev->stream_id)
     return NULL;
@@ -99,10 +99,10 @@ char *dope_get_bindarg(l4re_event_t *ev)
   return cb->arg;
 }
 
-void dope_process_event(l4re_event_t *ev);
+L4_CV void dope_process_event(l4re_event_t *ev);
 
 /*** INTERFACE: PROCESS SINGLE DOpE EVENT ***/
-void dope_process_event(l4re_event_t *ev)
+L4_CV void dope_process_event(l4re_event_t *ev)
 {
   if (!ev->stream_id)
     return;
@@ -114,12 +114,12 @@ void dope_process_event(l4re_event_t *ev)
   cb->callback(ev, cb->arg);
 }
 
-void dope_deinit_app(void) {}
+L4_CV void dope_deinit_app(void) {}
 
 
 /*** INTERFACE: DISCONNECT FROM DOpE ***
  *
  * FIXME: wait for the finishing of the current command and block net commands
  */
-void dope_deinit(void) {}
+L4_CV void dope_deinit(void) {}
 
index adb77c2372fc245edeba8902ebb301b05386f2ac..47dc03fc8ff68f9cd137579289753b3c23a69748 100644 (file)
@@ -2,7 +2,7 @@ PKGDIR        ?= ../../..
 L4DIR         ?= $(PKGDIR)/../..
 
 TARGET         = lib4dope.a
-REQUIRES_LIBS  = libpthread
+REQUIRES_LIBS  = libpthread l4re_c-util
 PRIVATE_INCDIR = $(PKGDIR)/lib/dope/include \
                  $(PKGDIR)/server/include \
                  $(PKGDIR)/include
index 9cf75f18ecee76ae9aee1c8ef74ad33ad93b9e24..dfd7cb74f32dff5996f1f7c45cf824c73254fe33 100644 (file)
@@ -23,13 +23,13 @@ int dope_req(char *res, unsigned long res_max, const char *cmd)
   if (!cmd || l4_is_invalid_cap(dope_server))
     return -1;
 
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dope::Dope_app_::Cmd_req)
-     << L4::ipc_buf_cp_out(cmd, strlen(cmd));
+     << L4::Ipc::Buf_cp_out<const char>(cmd, strlen(cmd));
 
   l4_msgtag_t r = io.call(dope_server, Dope::Protocol::App);
 
-  io >> L4::ipc_buf_cp_in(res, res_max);
+  io >> L4::Ipc::Buf_cp_in<char>(res, res_max);
 
   res[res_max] = 0;
   return l4_error(r);
@@ -57,9 +57,9 @@ int dope_cmd(const char *cmd)
   if (!cmd || l4_is_invalid_cap(dope_server))
     return -1;
 
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dope::Dope_app_::Cmd)
-     << L4::ipc_buf_cp_out(cmd, strlen(cmd));
+     << L4::Ipc::Buf_cp_out<const char>(cmd, strlen(cmd));
 
   l4_msgtag_t r = io.call(dope_server, Dope::Protocol::App);
   return l4_error(r);
@@ -83,14 +83,14 @@ int dope_cmdf(const char *format, ...)
 
 void *dope_vscr_get_fb(const char *s)
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   L4::Cap<L4Re::Dataspace> ds;
 
   ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
 
   io << L4::Opcode(Dope::Dope_app_::Vscreen_get_fb)
-     << L4::ipc_buf_cp_out(s, strlen(s));
-  io << L4::Small_buf(ds.cap(), 0);
+     << L4::Ipc::Buf_cp_out<const char>(s, strlen(s));
+  io << L4::Ipc::Small_buf(ds.cap(), 0);
 
   l4_msgtag_t r = io.call(dope_server, Dope::Protocol::App);
 
@@ -119,7 +119,7 @@ void vscr_server_waitsync(void *x)
 
 long dope_get_keystate(long keycode)
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dope::Dope_app_::Get_keystate) << keycode;
   l4_msgtag_t r = io.call(dope_server, Dope::Protocol::App);
 
index d1ab8845847abc0c7e539db39bb97d5e864b7024..dcb1fd4a7f0f31253637b22a15acdd2e6d0b960f 100644 (file)
@@ -50,17 +50,17 @@ void dopelib_usleep(int usec) {
        l4_sleep(usec/1000);
 }
 
-void dope_process_event(l4re_event_t *ev, void *data);
+L4_CV void dope_process_event(l4re_event_t *ev, void *data);
 
 /*** INTERFACE: HANDLE EVENTLOOP OF A DOpE CLIENT ***/
-void dope_eventloop(void)
+L4_CV void dope_eventloop(void)
 {
   l4re_event_buffer_consumer_process(&ev_buf, ev_irq,
                                      pthread_getl4cap(pthread_self()), NULL,
                                      dope_process_event);
 }
 
-l4re_event_t *dope_event_get(void)
+L4_CV l4re_event_t *dope_event_get(void)
 {
   return l4re_event_buffer_next(&ev_buf);
 }
@@ -69,7 +69,7 @@ l4re_event_t *dope_event_get(void)
  *
  * return 0 on success, != 0 otherwise
  */
-long dope_init(void)
+L4_CV long dope_init(void)
 {
   static int initialized;
   long ds_size;
@@ -90,6 +90,9 @@ long dope_init(void)
   INFO(printf("DOpElib(dope_init): found some DOpE.\n"));
 
   ev_ds = l4re_util_cap_alloc();
+  if (l4_is_invalid_cap(ev_ds))
+    return -L4_ENOMEM;
+
   ev_irq = l4re_util_cap_alloc();
 
   if (l4_is_invalid_cap(ev_irq))
index 03e854bb5a5da3af126f4b6ace0b524b44e31e5d..fafc6365792a96f2c77d5ab33f2977c11bdced52 100644 (file)
@@ -41,8 +41,6 @@
 #include <l4/sys/typeinfo_svr>
 #include <l4/cxx/exceptions>
 
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 #include <l4/cxx/minmax>
 
 #include <l4/re/protocols>
@@ -224,13 +222,13 @@ class Dope_app : public Dope_base
 {
 public:
   explicit Dope_app(const char *configstr);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
-  int dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
+  int dispatch_dope_app(l4_umword_t, L4::Ipc::Iostream &ios);
 
-  int client_cmd(L4::Ipc_iostream &ios);
-  int client_cmd_req(L4::Ipc_iostream &ios);
-  int client_vscreen_get_fb(L4::Ipc_iostream &ios);
-  int client_get_keystate(L4::Ipc_iostream &ios);
+  int client_cmd(L4::Ipc::Iostream &ios);
+  int client_cmd_req(L4::Ipc::Iostream &ios);
+  int client_vscreen_get_fb(L4::Ipc::Iostream &ios);
+  int client_get_keystate(L4::Ipc::Iostream &ios);
 };
 
 Dope_app::Dope_app(const char *configstr)
@@ -260,27 +258,27 @@ Dope_app::Dope_app(const char *configstr)
   INFO(printf("Server(init_app): application init request. appname=%s\n", appname));
 }
 
-int Dope_app::client_cmd(L4::Ipc_iostream &ios)
+int Dope_app::client_cmd(L4::Ipc::Iostream &ios)
 {
   unsigned long len;
   char buf_in[256];
 
   len = sizeof(buf_in);
-  ios >> L4::ipc_buf_cp_in(buf_in, len);
+  ios >> L4::Ipc::Buf_cp_in<char>(buf_in, len);
   buf_in[len] = 0;
 
   cmd(buf_in);
   return -L4_EOK;
 }
 
-int Dope_app::client_cmd_req(L4::Ipc_iostream &ios)
+int Dope_app::client_cmd_req(L4::Ipc::Iostream &ios)
 {
   unsigned long len;
   char buf_in[256];
   char buf_out[256];
 
   len = sizeof(buf_in);
-  ios >> L4::ipc_buf_cp_in(buf_in, len);
+  ios >> L4::Ipc::Buf_cp_in<char>(buf_in, len);
   buf_in[len] = 0;
 
   cmd_ret(buf_in, buf_out, sizeof(buf_out));
@@ -292,19 +290,19 @@ int Dope_app::client_cmd_req(L4::Ipc_iostream &ios)
       buf_out[sizeof(buf_out) - 1] = 0;
     }
 
-  ios << L4::ipc_buf_cp_out(buf_out, len);
+  ios << L4::Ipc::Buf_cp_out<char>(buf_out, len);
 
   return -L4_EOK;
 }
 
-int Dope_app::client_vscreen_get_fb(L4::Ipc_iostream &ios)
+int Dope_app::client_vscreen_get_fb(L4::Ipc::Iostream &ios)
 {
   unsigned long len;
   char buf_in[30];
   char buf[40];
 
   len = sizeof(buf_in);
-  ios >> L4::ipc_buf_cp_in(buf_in, len);
+  ios >> L4::Ipc::Buf_cp_in<char>(buf_in, len);
   buf_in[len] = 0;
 
   snprintf(buf, sizeof(buf), "%s.map()", buf_in);
@@ -315,7 +313,7 @@ int Dope_app::client_vscreen_get_fb(L4::Ipc_iostream &ios)
   return -L4_EOK;
 }
 
-int Dope_app::client_get_keystate(L4::Ipc_iostream &ios)
+int Dope_app::client_get_keystate(L4::Ipc::Iostream &ios)
 {
   long x;
   ios >> x; // get keycode
@@ -324,7 +322,7 @@ int Dope_app::client_get_keystate(L4::Ipc_iostream &ios)
   return -L4_EOK;
 }
 
-int Dope_app::dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios)
+int Dope_app::dispatch_dope_app(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
@@ -344,7 +342,7 @@ int Dope_app::dispatch_dope_app(l4_umword_t, L4::Ipc_iostream &ios)
     };
 }
 
-int Dope_app::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+int Dope_app::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -369,7 +367,7 @@ class Dope_fb : public L4Re::Util::Video::Goos_svr,
 {
 public:
   explicit Dope_fb(L4::Ipc::Istream &is);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   virtual int refresh(int x, int y, int w, int h);
 };
@@ -517,7 +515,7 @@ int Dope_fb::refresh(int x, int y, int w, int h)
   return L4_EOK;
 }
 
-int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -539,11 +537,11 @@ int Dope_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
 class Controller : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Controller::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -603,10 +601,10 @@ struct My_loop_hooks :
   public L4::Ipc_svr::Default_timeout,
   public L4::Ipc_svr::Compound_reply
 {
-  void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
+  void setup_wait(L4::Ipc::Istream &istr, L4::Ipc_svr::Reply_mode)
   {
     istr.reset();
-    istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 };
diff --git a/l4/pkg/drivers-frst/uart/include/uart_leon3.h b/l4/pkg/drivers-frst/uart/include/uart_leon3.h
new file mode 100644 (file)
index 0000000..151bad1
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *          Björn Döbel <doebel@os.inf.tu-dresden.de>
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#ifndef L4_CXX_UART_LEON3_H__
+#define L4_CXX_UART_LEON3_H__
+
+#include "uart_base.h"
+
+namespace L4
+{
+  class Uart_leon3 : public Uart
+  {
+  private:
+    unsigned long _base;
+
+    inline unsigned long rd(unsigned long reg) const;
+    inline void wr(unsigned long reg, unsigned long val) const;
+
+  public:
+    Uart_leon3(int rx_irq, int tx_irq)
+       : Uart(rx_irq, tx_irq), _base(~0UL) {}
+    bool startup(unsigned long base);
+    void shutdown();
+    bool enable_rx_irq(bool enable = true);
+    bool enable_tx_irq(bool enable = true);
+    bool change_mode(Transfer_mode m, Baud_rate r);
+    int get_char(bool blocking = true) const;
+    int char_avail() const;
+    inline void out_char(char c) const;
+    int write(char const *s, unsigned long count) const;
+  };
+};
+
+#endif
index f4679ae56fcebefb03381d422134d785145c8203..ccd7f722dc72e339d3ec384cd7649188a2e19aef 100644 (file)
@@ -1,14 +1,14 @@
 PKGDIR         ?= ../..
 L4DIR          ?= $(PKGDIR)/../..
 
-SRC_CC        += uart_dummy.cc uart_pl011.cc uart_sa1000.cc \
-                  uart_pxa.cc uart_omap35x.cc uart_imx.cc \
-                 uart_s3c2410.cc uart_of.cc
+SRC_CC      += uart_dummy.cc uart_pl011.cc uart_sa1000.cc \
+               uart_pxa.cc uart_omap35x.cc uart_imx.cc \
+               uart_s3c2410.cc uart_of.cc uart_leon3.cc
 SYSTEMS                = $(SYSTEMS_PLAIN)
 TARGET         = libdrivers_uart.a
 PC_FILENAME     = drivers_uart
 
-PRIVATE_INCDIR += $(SRC_DIR)/../include 
+PRIVATE_INCDIR += $(SRC_DIR)/../include
 
 INCLUDE_MAKE_RULES = $(SRC_DIR)/*/Make.rules
 
diff --git a/l4/pkg/drivers-frst/uart/src/uart_leon3.cc b/l4/pkg/drivers-frst/uart/src/uart_leon3.cc
new file mode 100644 (file)
index 0000000..e02d3dd
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *          Björn Döbel <doebel@os.inf.tu-dresden.de>
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include "uart_leon3.h"
+
+namespace L4
+{
+  enum {
+    DATA_REG   = 0x00,
+    STATUS_REG = 0x04,
+    CTRL_REG   = 0x08,
+    SCALER_REG = 0x0C,
+
+    DATA_MASK  = 0x0F,
+
+    STATUS_DR  = 0x001, // data ready
+    STATUS_TS  = 0x002, // transmit shift empty
+    STATUS_TE  = 0x004, // transmit fifo empty
+    STATUS_BR  = 0x008, // BREAK received
+    STATUS_OV  = 0x010, // overrun
+    STATUS_PE  = 0x020, // parity error
+    STATUS_FE  = 0x040, // framing error
+    STATUS_TH  = 0x080, // transmit fifo half-full
+    STATUS_RH  = 0x100, // recv fifo half-full
+    STATUS_TF  = 0x200, // transmit fifo full
+    STATUS_RF  = 0x400, // recv fifo full
+
+    STATUS_TCNT_MASK  = 0x3F,
+    STATUS_TCNT_SHIFT = 20,
+    STATUS_RCNT_MASK  = 0x3F,
+    STATUS_RCNT_SHIFT = 26,
+
+    CTRL_RE    = 0x001,
+    CTRL_TE    = 0x002,
+    CTRL_RI    = 0x004,
+    CTRL_TI    = 0x008,
+    CTRL_PS    = 0x010,
+    CTRL_PE    = 0x020,
+    CTRL_FL    = 0x040,
+    CTRL_LB    = 0x080,
+    CTRL_EC    = 0x100,
+    CTRL_TF    = 0x200,
+    CTRL_RF    = 0x400,
+
+    SCALER_MASK = 0xFFF,
+  };
+
+
+  unsigned long Uart_leon3::rd(unsigned long reg) const
+  {
+    volatile unsigned long *r = (unsigned long*)(_base + reg);
+    return *r;
+  }
+
+  void Uart_leon3::wr(unsigned long reg, unsigned long val) const
+  {
+    volatile unsigned long *r = (unsigned long*)(_base + reg);
+    *r = val;
+  }
+
+  bool Uart_leon3::startup(unsigned long base)
+  {
+    _base = base;
+
+    return true;
+  }
+
+  void Uart_leon3::shutdown()
+  { }
+
+  bool Uart_leon3::enable_rx_irq(bool /*enable*/)
+  {
+    return false;
+  }
+
+  bool Uart_leon3::enable_tx_irq(bool /*enable*/) { return false; }
+
+  bool Uart_leon3::change_mode(Transfer_mode, Baud_rate r)
+  {
+    if (r != 115200)
+      return false;
+
+    return true;
+  }
+
+  int Uart_leon3::get_char(bool blocking) const
+  {
+    while (!char_avail())
+      if (!blocking)
+        return -1;
+
+    return rd(DATA_REG) & DATA_MASK;
+  }
+
+  int Uart_leon3::char_avail() const
+  {
+    return 0;
+  }
+
+  void Uart_leon3::out_char(char c) const
+  {
+    while (!(rd(STATUS_REG) & STATUS_TE))
+      ;
+    wr(DATA_REG, c);
+  }
+
+  int Uart_leon3::write(char const *s, unsigned long count) const
+  {
+    unsigned long c = count;
+    while (c)
+      {
+        if (*s == 10)
+          out_char(13);
+        out_char(*s++);
+        --c;
+      }
+
+    return count;
+  }
+};
index b1774431d1a9eaad1052768f1d6a216f2f192c21..37dd4f47f6cf769a6f26c089f4446f5d50e987e3 100644 (file)
@@ -4,6 +4,7 @@ L4DIR           ?= $(PKGDIR)/../..
 TARGET                   = ex_clntsrv-server ex_clntsrv-client
 SRC_CC_ex_clntsrv-server = server.cc
 SRC_CC_ex_clntsrv-client = client.cc
+REQUIRES_LIBS            = cxx_libc_io cxx_io
 
 include $(L4DIR)/mk/prog.mk
 
index 48e110ce3caf93fccfec3d383002c905875d69f3..a91ffc4e94b41dcefbebcffe0b64fbca3d079d4b 100644 (file)
@@ -21,7 +21,7 @@ int
 func_neg_call(L4::Cap<void> const &server, l4_uint32_t *result,
               l4_uint32_t val)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << l4_umword_t(Opcode::func_neg) << val;
   l4_msgtag_t res = s.call(server.cap());
   if (l4_ipc_error(res, l4_utcb()))
@@ -34,7 +34,7 @@ int
 func_sub_call(L4::Cap<void> const &server, l4_uint32_t *result,
               l4_uint32_t val1, l4_uint32_t val2)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << l4_umword_t(Opcode::func_sub) << val1 << val2;
   l4_msgtag_t res = s.call(server.cap(), Protocol::Calc);
   if (l4_ipc_error(res, l4_utcb()))
index fb7f65ca4a75759e71784a0a81df27a6712e24ad..f8aaf40f5e40629dcd058f865e12c06eb0dd0ba7 100644 (file)
@@ -12,8 +12,6 @@
 #include <l4/re/util/cap_alloc>
 #include <l4/re/util/object_registry>
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 
 #include "shared.h"
 
@@ -22,11 +20,11 @@ static L4Re::Util::Registry_server<> server;
 class Calculation_server : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Calculation_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Calculation_server::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
index 31a7707bca9ab0116c1deb24750dc0ecfa0b5882..f54cec4bdfc7bb1c29120152a662fe52e6cb8484 100644 (file)
@@ -47,11 +47,11 @@ public:
   /**
    * Dispatch function, dealing with remote requests.
    */
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 
-int My_server_obj::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+int My_server_obj::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   // we don't care about the original object reference, however
   // we could read out the access rights from the lowest 2 bits
@@ -103,10 +103,10 @@ public:
    * Dispatch function, dealing with remote requests.
    * This is the ISR.
    */
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
-int Shm_observer::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+int Shm_observer::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   // we don't care about the original object reference, however
   // we could read out the access rights from the lowest 2 bits
index 40c6439032368898c7204352dbef336f9ab07b7e..229cbe838e8653a9f68aef354c7055df4b6c7c13 100644 (file)
@@ -20,7 +20,7 @@
 int
 func_smap_call(L4::Cap<void> const &server)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4_addr_t addr = 0;
   int err;
 
@@ -34,7 +34,7 @@ func_smap_call(L4::Cap<void> const &server)
 
   s << l4_umword_t(Opcode::Do_map)
     << (l4_addr_t)addr;
-  s << L4::Rcv_fpage::mem((l4_addr_t)addr, L4_PAGESHIFT, 0);
+  s << L4::Ipc::Rcv_fpage::mem((l4_addr_t)addr, L4_PAGESHIFT, 0);
   l4_msgtag_t res = s.call(server.cap(), Protocol::Map_example);
   if (l4_ipc_error(res, l4_utcb()))
     return 1; // failure
index 3e5200dcc7d6dda807459a6af7ab41ee210ef731..6b95dac6044ed2f0f63355721d08ad581564dcd6 100644 (file)
@@ -12,8 +12,6 @@
 #include <l4/re/util/cap_alloc>
 #include <l4/re/util/object_registry>
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 
 #include "shared.h"
 
@@ -24,11 +22,11 @@ static L4Re::Util::Registry_server<> server;
 class Smap_server : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Smap_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Smap_server::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
@@ -49,7 +47,7 @@ Smap_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
       snprintf(page_to_map, sizeof(page_to_map), "Hello from the server!");
       printf("Sending to client\n");
       // send page
-      ios << L4::Snd_fpage::mem((l4_addr_t)page_to_map, L4_PAGESHIFT,
+      ios << L4::Ipc::Snd_fpage::mem((l4_addr_t)page_to_map, L4_PAGESHIFT,
                                 L4_FPAGE_RO, snd_base);
       return L4_EOK;
     default:
index 82c6dfbcec8c25752add8e4e8d3c8b15b4bd3dac..65b07e767e9bd74c4710f2012ce2bdffd5cc1140 100644 (file)
@@ -3,7 +3,7 @@ L4DIR           ?= $(PKGDIR)/../..
 
 TARGET         = ex_vcpu
 SRC_CC         = vcpu.cc
-REQUIRES_LIBS   = libvcpu
+REQUIRES_LIBS   = libvcpu cxx_io cxx_libc_io
 DEPENDS_PKGS    = libvcpu
 
 include $(L4DIR)/mk/prog.mk
index 980d3554c5b4b8e2d50478b00eaf21c7a1c280c1..11aca96759e73053bfd43117578f1993f57eb757 100644 (file)
@@ -34,7 +34,7 @@ public:
   ~Phys_fb() throw() {}
   virtual bool setup_drv(Prog_args *pa) = 0;
   void setup_ds(char const *name);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   int map_hook(l4_addr_t offs, unsigned long flags,
                l4_addr_t min, l4_addr_t max);
 
index 9b9cae7cdf16ef7b997196dc18fb3a9ddca91b2b..b65b0c88ae298815999a557225e7f6b9899de6f7 100644 (file)
@@ -67,7 +67,7 @@ Phys_fb::map_hook(l4_addr_t offs, unsigned long flags,
 }
 
 int
-Phys_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Phys_fb::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index 3a2008204e8dfb4850ac57cb1f11322f46a9a13c..2c400e91f912b46ca43f593a0f8a495d3c4c6c19 100644 (file)
@@ -76,7 +76,7 @@ public:
   typedef L4Re::Util::Vcon_svr<Terminal>          Vcon_svr;
 
   explicit Terminal();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   void trigger() { _irq.trigger(); }
 
@@ -452,7 +452,7 @@ Terminal::vcon_get_attr(l4_vcon_attr_t *attr) throw()
 }
 
 int
-Terminal::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Terminal::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -473,11 +473,11 @@ Terminal::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
 class Controller : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Controller::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -524,10 +524,10 @@ struct My_hooks
     public L4::Ipc_svr::Ignore_errors,
     public L4::Ipc_svr::Compound_reply
 {
-  void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
+  void setup_wait(L4::Ipc::Istream &istr, L4::Ipc_svr::Reply_mode)
   {
     istr.reset();
-    istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 };
index 294a7a67077d63f6d608712df31c1bffd81fcf60..2642b063cf4425a7d98bfc5f1a0701d9e3b3bf74 100644 (file)
@@ -5,7 +5,7 @@ TARGET          = fuxfprov
 SYSTEMS                = x86-l4f
 SRC_CC         = main.cc
 DEPENDS_PKGS   = zlib l4util
-REQUIRES_LIBS   = zlib l4util libsupc++ libl4revfs-fs-fuxfs
+REQUIRES_LIBS   = zlib l4util libsupc++ libl4revfs-fs-fuxfs cxx_libc_io cxx_io
 
 include $(L4DIR)/mk/prog.mk
 
index e94d045db10685fc2ab10e493f38dcd5427f41f4..3849ff7f9557b43f1086ec6631ec717a280c1786 100644 (file)
@@ -97,14 +97,14 @@ class Ds : public L4::Server_object
 {
 public:
   explicit Ds(const char *fname);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 private:
   unsigned long flags() { return 0; }
   unsigned long _size;
   L4::Cap<L4Re::Dataspace> mem_ds;
   int map(l4_addr_t offs, l4_addr_t hot_spot, unsigned long flags,
-          l4_addr_t min, l4_addr_t max, L4::Snd_fpage &snd_fpage);
+          l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &snd_fpage);
   unsigned evict_page();
 
   gzFile fd;
@@ -229,11 +229,11 @@ unsigned Ds::evict_page()
 }
 
 int Ds::map(l4_addr_t offs, l4_addr_t hot_spot, unsigned long flags,
-            l4_addr_t, l4_addr_t, L4::Snd_fpage &snd_fpage)
+            l4_addr_t, l4_addr_t, L4::Ipc::Snd_fpage &snd_fpage)
 {
   printf("map: offs=%lx hot_spot=%lx flags=%lx\n", offs, hot_spot, flags);
 
-  snd_fpage = L4::Snd_fpage();
+  snd_fpage = L4::Ipc::Snd_fpage();
 
   if (offs > l4_round_page(_size))
     return -L4_ENOENT;
@@ -273,13 +273,13 @@ int Ds::map(l4_addr_t offs, l4_addr_t hot_spot, unsigned long flags,
 
   hot_spot = l4_trunc_page(hot_spot);
 
-  snd_fpage = L4::Snd_fpage(l4_fpage((l4_addr_t)mem(idx), L4_PAGESHIFT, L4_FPAGE_RO),
+  snd_fpage = L4::Ipc::Snd_fpage(l4_fpage((l4_addr_t)mem(idx), L4_PAGESHIFT, L4_FPAGE_RO),
                             hot_spot);
 
   return -L4_EOK;
 }
 
-int Ds::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+int Ds::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -300,7 +300,7 @@ int Ds::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
           unsigned long flags;
           ios >> offset >> spot >> flags;
 
-          L4::Snd_fpage fp;
+          L4::Ipc::Snd_fpage fp;
           long int ret = map(offset, spot, !read_only && (flags & 1), 0, ~0, fp);
 
           if (ret == L4_EOK)
@@ -322,7 +322,7 @@ class Fprov_server : public L4::Server_object
 {
 public:
   Fprov_server();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 private:
   enum {
@@ -330,8 +330,8 @@ private:
     Buf_size = 64 << 10,
   };
 
-  int get_file1(const char *fname, L4::Ipc_iostream &ios);
-  int get_file2(const char *fname, L4::Ipc_iostream &ios);
+  int get_file1(const char *fname, L4::Ipc::Iostream &ios);
+  int get_file2(const char *fname, L4::Ipc::Iostream &ios);
 
   char *_buf;
 };
@@ -344,18 +344,18 @@ Fprov_server::Fprov_server()
 }
 
 int
-Fprov_server::get_file2(char const *fname, L4::Ipc_iostream &ios)
+Fprov_server::get_file2(char const *fname, L4::Ipc::Iostream &ios)
 {
   printf("open: %s\n", fname);
 
   Ds *ds = new Ds(fname);
 
-  ios << L4::Snd_fpage(ds->obj_cap().fpage(L4_FPAGE_RO));
+  ios << L4::Ipc::Snd_fpage(ds->obj_cap().fpage(L4_FPAGE_RO));
   return -L4_EOK;
 }
 
 int
-Fprov_server::get_file1(char const *fname, L4::Ipc_iostream &ios)
+Fprov_server::get_file1(char const *fname, L4::Ipc::Iostream &ios)
 {
   gzFile fd = NULL;
   long fread;
@@ -453,13 +453,13 @@ Fprov_server::get_file1(char const *fname, L4::Ipc_iostream &ios)
   L4Re::Env::env()->rm()->detach(addr, 0);
   gzclose(fd);
 
-  ios << L4::Snd_fpage(ds_cap.fpage(L4_FPAGE_RO));
+  ios << L4::Ipc::Snd_fpage(ds_cap.fpage(L4_FPAGE_RO));
 
   return 0;
 }
 
 int
-Fprov_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Fprov_server::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
@@ -474,15 +474,9 @@ Fprov_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
     {
     case L4Re::Namespace_::Query:
         {
-          char const *filenamep = 0;
           char filename[Max_filename_len];
           unsigned long len = Max_filename_len;
-          ios >> L4::ipc_buf_in(filenamep, len);
-
-          // copy out of utcb
-          if (Max_filename_len - 1 < len)
-            len = Max_filename_len - 1;
-          memcpy(filename, filenamep, len);
+          ios >> L4::Ipc::Buf_cp_in<char>(filename, len);
           filename[len] = 0;
 
           return get_file1(filename, ios);
index d812dd025a90f73df767b69443e5decc8c930b10..fc880c3b9df3deedc38b38076e415b9055c885da 100644 (file)
@@ -33,11 +33,11 @@ struct l4input_ops {
 };
 
 /** L4EVDEV input event handler (hardware drivers) **/
-struct l4input_ops * l4input_internal_l4evdev_init(void (*cb)(struct l4input *));
+struct l4input_ops * l4input_internal_l4evdev_init(L4_CV void (*cb)(struct l4input *));
 void l4input_internal_l4evdev_exit(void);
 
 /** UX backend */
-struct l4input_ops * l4input_internal_ux_init(void (*cb)(struct l4input *));
+struct l4input_ops * l4input_internal_ux_init(L4_CV void (*cb)(struct l4input *));
 
 /** INPUT SYSTEM **/
 int  l4input_internal_atkbd_init(void);
index ba2fcdb7643a831cc803896616f0a1d6871e0b3a..d910f4979f5563a2035a4b8273870409483b1bcb 100644 (file)
 #include <l4/input/libinput.h>
 #include <l4/sys/err.h>
 
-int l4input_ispending(void)
+L4_CV int l4input_ispending(void)
 {
   return 0;
 }
 
-int l4input_flush(void *buffer, int count)
+L4_CV int l4input_flush(void *buffer, int count)
 {
   (void)buffer; (void)count;
   return 0;
 }
 
-int l4input_pcspkr(int tone)
+L4_CV int l4input_pcspkr(int tone)
 {
   (void)tone;
   return -L4_ENODEV;
 }
 
-int l4input_init(int prio, void (*handler)(struct l4input *))
+L4_CV int l4input_init(int prio, L4_CV void (*handler)(struct l4input *))
 {
   (void)prio; (void)handler;
   return 0;
index 9f2b34a5273ac01ecffbecbd7873a668a13cebb3..a13ec2eeda3dc9916d97fbb130caeb26454e0030 100644 (file)
@@ -46,7 +46,7 @@ int l4input_ispending()
                return 0;
 }
 
-int l4input_flush(void *buf, int count)
+L4_CV int l4input_flush(void *buf, int count)
 {
        if (ops->flush)
                return ops->flush(buf, count);
@@ -54,7 +54,7 @@ int l4input_flush(void *buf, int count)
                return 0;
 }
 
-int l4input_pcspkr(int tone)
+L4_CV int l4input_pcspkr(int tone)
 {
        if (ops->pcspkr)
                return ops->pcspkr(tone);
@@ -77,7 +77,7 @@ int l4input_pcspkr(int tone)
         return error; }
 
 /** L4INPUT LIBRARY INITIALIZATION **/
-int l4input_init(int prio, void (*handler)(struct l4input *))
+L4_CV int l4input_init(int prio, L4_CV void (*handler)(struct l4input *))
 {
        if (!l4util_kip_kernel_is_ux(l4re_kip())) {
                printf("L4INPUT native mode activated\n");
index a2474f3e55c37fb7548c546d67dcd42b69bf1d11..ac213dc165b98f7460f308d3cbe964dd426bfa88 100644 (file)
@@ -299,7 +299,7 @@ static inline int filter_event(struct input_handle *handle, unsigned int type,
 
 
 /** HANDLE INCOMING EVENTS (CALLBACK VARIANT) **/
-static void(*callback)(struct l4input *) = NULL;
+static L4_CV void(*callback)(struct l4input *) = NULL;
 
 static void l4evdev_event_cb(struct input_handle *handle, unsigned int type,
                              unsigned int code, int value)
@@ -567,7 +567,7 @@ static struct l4input_ops ops = {
        l4evdev_ispending, l4evdev_flush, l4evdev_pcspkr
 };
 
-struct l4input_ops * l4input_internal_l4evdev_init(void (*cb)(struct l4input *))
+struct l4input_ops * l4input_internal_l4evdev_init(L4_CV void (*cb)(struct l4input *))
 {
        if (cb) {
                /* do callbacks */
index 00374c4d7db8d6ebe9bb5dbc8da6b21e616629dd..a9faf585c947855d417255215acd3e9b01b88104 100644 (file)
@@ -41,7 +41,7 @@ enum {
 
 static int input_pos;
 static struct l4input *input_mem;
-static void (*input_handler)(struct l4input *);
+static L4_CV void (*input_handler)(struct l4input *);
 
 static int dequeue_event(struct l4input *ev)
 {
@@ -171,7 +171,7 @@ static int ux_flush(void *buffer, int count)
 
 static struct l4input_ops ops = { ux_ispending, ux_flush, 0 };
 
-struct l4input_ops * l4input_internal_ux_init(void (*handler)(struct l4input *))
+struct l4input_ops * l4input_internal_ux_init(L4_CV void (*handler)(struct l4input *))
 {
   input_handler = handler;
 
index a735f5c914ea48837624eabe3562a0d51cd0b806..1f955f2f5db5c38bcf4a2d63c8cdcee9e712f61e 100644 (file)
@@ -6,7 +6,7 @@
 # Please see the COPYING-GPL-2 file for details.
 
 
-// multi-core EB
+# multi-core EB (PB11MP)
 hw-root
 {
   CTRL => new Device()
diff --git a/l4/pkg/io/config/arm-rv-eb-pbx.devs b/l4/pkg/io/config/arm-rv-eb-pbx.devs
new file mode 100644 (file)
index 0000000..8158a6e
--- /dev/null
@@ -0,0 +1,81 @@
+# vim:set ft=ioconfig:
+
+# ARM Realview PBX Platform
+hw-root
+{
+  CTRL => new Device()
+  {
+    .hid = "System Control";
+    new-res Mmio(0x10000000 .. 0x10000fff);
+  }
+
+  LCD => new Device()
+  {
+    .hid = "AMBA PL110";
+    new-res Mmio(0x10020000 .. 0x10020fff);
+    new-res Irq(55);
+  }
+
+  KBD => new Device()
+  {
+    .hid = "AMBA KMI Kbd";
+    new-res Irq(52);
+    new-res Mmio(0x10006000 .. 0x10006fff);
+  }
+
+  MOUSE => new Device()
+  {
+    .hid = "AMBA KMI mou";
+    new-res Mmio(0x10007000 .. 0x10007fff);
+    new-res Irq(53);
+  }
+
+  GPIO0 => new Device()
+  {
+    .hid = "AMBA PL061 dev0";
+    new-res Mmio(0x10013000 .. 0x10013fff);
+    new-res Irq(38);
+  }
+
+  GPIO1 => new Device()
+  {
+    .hid = "AMBA PL061 dev1";
+    new-res Mmio(0x10014000 .. 0x10014fff);
+    new-res Irq(39);
+  }
+
+  COMPACTFLASH => new Device()
+  {
+    .hid = "compactflash";
+    new-res Mmio(0x18000000 .. 0x1b000fff);
+    new-res Irq(59);
+  }
+
+  AACI => new Device()
+  {
+    .hid = "aaci";
+    new-res Mmio(0x10004000 .. 0x10004fff);
+    new-res Irq(51);
+  }
+
+  NIC => new Device()
+  {
+    .hid = "smsc911x";
+    new-res Mmio(0x4e000000 .. 0x4e000fff);
+    new-res Irq(41);
+  }
+
+  USB => new Device()
+  {
+    .hid = "usb";
+    new-res Mmio(0x4f000000 .. 0x4fffffff);
+    new-res Irq(61);
+  }
+
+  RTC => new Device()
+  {
+    .hid = "rtc";
+    new-res Mmio(0x10017000 .. 0x10017fff);
+    new-res Irq(42);
+  }
+}
index 1bee1be3a3d7851636ccacc0e872c50d0d46832a..0c36c0238d7c7c23f36800d4767041da6767f555 100644 (file)
@@ -12,7 +12,7 @@
 #include <cstdio>
 #include <cstdarg>
 
-static unsigned _debug_level = 2;
+static unsigned _debug_level = 1;
 
 void set_debug_level(unsigned level)
 {
index cd872d08489f746ce0dcf4e1b3e2efe988d91745..eb6d872b2b7a47335259a7a9a1d34790ffdd8611 100644 (file)
@@ -15,7 +15,7 @@
 #include <l4/re/error_helper>
 #include <l4/re/dataspace>
 #include <l4/util/kip.h>
-#include <l4/cxx/iostream>
+#include <l4/cxx/std_exc_io>
 
 #include "main.h"
 #include "hw_root_bus.h"
@@ -47,7 +47,8 @@ using L4Re::Util::Auto_cap;
 class Io_config_x : public Io_config
 {
 public:
-  Io_config_x() : _do_transparent_msi(false) {}
+  Io_config_x()
+  : _do_transparent_msi(false), _verbose_lvl(1) {}
 
   bool transparent_msi(Hw::Device *) const
   { return _do_transparent_msi; }
@@ -202,11 +203,15 @@ arg_init(int argc, char * const *argv, Io_config_x *cfg)
     {
       int optidx = 0;
       int c;
+      enum
+      {
+        OPT_TRANSPARENT_MSI   = 1,
+      };
 
       struct option opts[] =
       {
-        { "verbose",         0, 0, 'v' },
-        { "transparent-msi", 0, 0, 1 },
+        { "verbose",           0, 0, 'v' },
+        { "transparent-msi",   0, 0, OPT_TRANSPARENT_MSI },
         { 0, 0, 0, 0 },
       };
 
@@ -219,7 +224,7 @@ arg_init(int argc, char * const *argv, Io_config_x *cfg)
         case 'v':
           _my_cfg.inc_verbosity();
           break;
-        case 1:
+        case OPT_TRANSPARENT_MSI:
          d_printf(DBG_INFO, "Enabling transparent MSIs\n");
           cfg->set_transparent_msi(true);
           break;
@@ -237,7 +242,7 @@ run(int argc, char * const *argv)
   printf("Io service\n");
   set_debug_level(Io_config::cfg->verbose());
 
-  d_printf(DBG_ERR, "Verboseness level: %d\n", Io_config::cfg->verbose());
+  d_printf(DBG_INFO, "Verboseness level: %d\n", Io_config::cfg->verbose());
 
   res_init();
 
@@ -284,14 +289,14 @@ main(int argc, char * const *argv)
     }
   catch (L4::Runtime_error &e)
     {
-      L4::cerr << "FATAL uncought exception: " << e
-               << "\nterminating...\n";
+      std::cerr << "FATAL uncought exception: " << e
+                << "\nterminating...\n";
 
     }
   catch (...)
     {
-      L4::cerr << "FATAL uncought exception of unknown type\n"
-               << "terminating...\n";
+      std::cerr << "FATAL uncought exception of unknown type\n"
+                << "terminating...\n";
     }
   return -1;
 }
index bc0d781b3352c8d2105f4044b5ef4936f10977ed..a280cdae862a0aacd8b047c88b80fe45e7f3d6ef 100644 (file)
@@ -13,8 +13,6 @@
 #include <l4/re/error_helper>
 
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 
 #include "server.h"
 
@@ -27,10 +25,10 @@ class Loop_hooks :
   public L4::Ipc_svr::Compound_reply
 {
 public:
-  static void setup_wait(L4::Ipc_istream &istr, bool)
+  static void setup_wait(L4::Ipc::Istream &istr, bool)
   {
     istr.reset();
-    istr << L4::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br()->bdr = 0;
   }
 
index 45a75149eca82f61b8009ed5e4495e4da92ee2b8..cde83ce41019031e63f57c4eda54bf68dcdf81f7 100644 (file)
@@ -10,8 +10,6 @@
 #include <l4/re/protocols>
 
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 
 #include <l4/re/env>
 #include <l4/re/namespace>
@@ -186,7 +184,7 @@ System_bus::dump_resources() const
 }
 
 int
-System_bus::request_resource(L4::Ipc_iostream &ios)
+System_bus::request_resource(L4::Ipc::Iostream &ios)
 {
   l4vbus_resource_t res;
   ios.get(res);
@@ -231,7 +229,7 @@ System_bus::request_resource(L4::Ipc_iostream &ios)
       if ((1UL << szl2) > sz)
        --szl2;
 
-      ios << L4::Snd_fpage::io(res.start, szl2, L4_FPAGE_RWX);
+      ios << L4::Ipc::Snd_fpage::io(res.start, szl2, L4_FPAGE_RWX);
       return L4_EOK;
     }
 
@@ -240,7 +238,7 @@ System_bus::request_resource(L4::Ipc_iostream &ios)
 }
 
 int
-System_bus::request_iomem(L4::Ipc_iostream &ios)
+System_bus::request_iomem(L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
@@ -275,10 +273,10 @@ System_bus::request_iomem(L4::Ipc_iostream &ios)
                                  addr, addr, addr + (*r)->size(), spot);
 
           // we also might want to do WB instead of UNCACHED...
-          ios << L4::Snd_fpage::mem(l4_trunc_size(addr, order), order,
+          ios << L4::Ipc::Snd_fpage::mem(l4_trunc_size(addr, order), order,
                                     L4_FPAGE_RWX, l4_trunc_page(spot),
-                                    L4::Snd_fpage::Map,
-                                    L4::Snd_fpage::Uncached);
+                                    L4::Ipc::Snd_fpage::Map,
+                                    L4::Ipc::Snd_fpage::Uncached);
          return L4_EOK;
        }
     }
@@ -286,7 +284,7 @@ System_bus::request_iomem(L4::Ipc_iostream &ios)
 };
 
 int
-System_bus::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+System_bus::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -310,7 +308,7 @@ System_bus::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
 }
 
 int
-System_bus::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
+System_bus::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
 {
   switch (func)
     {
index a1a2caa51365a8183866772c56e111ddbc00209f..289f43d5a9c0b201aebeda53b34fdc5dda81d876 100644 (file)
@@ -25,13 +25,13 @@ public:
   ~System_bus();
 
   // dispatch for the server object
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
-  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
+  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
   bool match_hw_feature(Hw::Dev_feature const *) const { return false; }
 
 private:
-  int request_resource(L4::Ipc_iostream &ios);
-  int request_iomem(L4::Ipc_iostream &ios);
+  int request_resource(L4::Ipc::Iostream &ios);
+  int request_iomem(L4::Ipc::Iostream &ios);
 
 public:
   bool resource_allocated(Resource const *) const;
index e52494cbcabff802700173d4f47c7df9eaab6e3a..6db3fefdae82f0caa7508b594286c9b238f6b5f8 100644 (file)
@@ -59,7 +59,7 @@ struct Match_hid
 };
 
 int
-Device::get_by_hid(L4::Ipc_iostream &ios)
+Device::get_by_hid(L4::Ipc::Iostream &ios)
 {
   l4vbus_device_handle_t child;
   unsigned long sz;
@@ -67,7 +67,7 @@ Device::get_by_hid(L4::Ipc_iostream &ios)
 
   int depth;
 
-  ios >> child >> depth >> L4::ipc_buf_in(hid, sz);
+  ios >> child >> depth >> L4::Ipc::Buf_in<char const>(hid, sz);
 
   //printf("look for '%s' in %p(%x) from %x\n", hid, this, _id, start);
   if (!hid || !sz)
@@ -99,7 +99,7 @@ Device::get_by_hid(L4::Ipc_iostream &ios)
 
 
 int
-Device::vbus_get_device(L4::Ipc_iostream &ios)
+Device::vbus_get_device(L4::Ipc::Iostream &ios)
 {
   l4vbus_device_t inf;
   inf.num_resources = resources()->size();
@@ -121,7 +121,7 @@ Device::vbus_get_device(L4::Ipc_iostream &ios)
 }
 
 int
-Device::vdevice_dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc_iostream &ios)
+Device::vdevice_dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc::Iostream &ios)
 {
   if (func & L4vbus_vdevice_generic)
     {
index d034aa11f814b10ca854267e142c37aaa14a07db..6561b2a366807fe124d252b715fda6b672e75e34 100644 (file)
@@ -34,7 +34,7 @@ class Dev_feature
 public:
   virtual ~Dev_feature() {}
   virtual bool match_hw_feature(Hw::Dev_feature const *) const = 0;
-  virtual int dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc_iostream &ios) = 0;
+  virtual int dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc::Iostream &ios) = 0;
   virtual Device *host() const = 0;
   virtual void set_host(Device *d) = 0;
 };
@@ -48,7 +48,7 @@ public:
   using Device_tree_mixin<Device>::end;
 
   // disptach helper for server object
-  int vdevice_dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc_iostream &ios);
+  int vdevice_dispatch(l4_umword_t obj, l4_uint32_t func, L4::Ipc::Iostream &ios);
 
   typedef std::vector<Dev_feature*> Feature_list;
 
@@ -98,8 +98,8 @@ public:
 
 protected:
   // helper functions
-  int get_by_hid(L4::Ipc_iostream &ios);
-  int vbus_get_device(L4::Ipc_iostream &ios);
+  int get_by_hid(L4::Ipc::Iostream &ios);
+  int vbus_get_device(L4::Ipc::Iostream &ios);
   Device *get_dev_by_id(l4vbus_device_handle_t id);
 
 
index 5b9cff8c3ac5da575167b3e97e3f52ed6c3c0748..6d6e60d4498017bcb18aaa46ef99546e58b5b158 100644 (file)
@@ -61,7 +61,7 @@ Sw_icu::~Sw_icu()
 }
 
 int
-Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
+Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &/*irqc*/)
 {
   if (tag.items() < 1)
     return -L4_EINVAL;
@@ -80,7 +80,7 @@ Sw_icu::bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
 }
 
 int
-Sw_icu::unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &/*irqc*/)
+Sw_icu::unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &/*irqc*/)
 {
   if (tag.items() < 1)
     return -L4_EINVAL;
@@ -180,10 +180,10 @@ Sw_icu::alloc_irq(unsigned flags, Io_irq_pin *be)
 
 
 int
-Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc_iostream &ios)
+Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc::Iostream &ios)
 {
   l4_umword_t op, irqn;
-  L4::Snd_fpage irqc;
+  L4::Ipc::Snd_fpage irqc;
   l4_msgtag_t tag;
   ios >> tag >> op >> irqn;
 
@@ -216,7 +216,7 @@ Sw_icu::dispatch(l4_umword_t /*obj*/, L4::Ipc_iostream &ios)
 }
 
 int
-Sw_icu::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
+Sw_icu::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
 {
   if (func != L4vbus_vicu_get_cap)
     return -L4_ENOSYS;
index 7382d8b9490e17e7066e28d710828e1af931f341..7b43981fa702188dfd17b83292390e484ea82317 100644 (file)
@@ -29,10 +29,10 @@ public:
   Sw_icu();
   virtual ~Sw_icu();
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   char const *hid() const { return "L40009"; }
-  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
   bool match_hw_feature(Hw::Dev_feature const *) const { return false; }
 
   bool add_irqs(Adr_resource const *r);
@@ -41,8 +41,8 @@ public:
   bool irqs_allocated(Adr_resource const *r);
 
 private:
-  int bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &irqc);
-  int unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Snd_fpage const &irqc);
+  int bind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &irqc);
+  int unbind_irq(l4_msgtag_t tag, unsigned irqn, L4::Ipc::Snd_fpage const &irqc);
   int unmask_irq(l4_msgtag_t tag, unsigned irqn);
   int set_mode(l4_msgtag_t tag, unsigned irqn, l4_umword_t mode);
 
index 120d5018d487b32a21aad1b02d496a6c2cf59bb1..c4275545bd22c9a8125515430216a4370330a9f9 100644 (file)
@@ -305,7 +305,7 @@ public:
   }
 
   bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
-  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream&)
+  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc::Iostream&)
   { return -L4_ENOSYS; }
   void set_host(Device *d) { _host = d; }
   Device *host() const { return _host; }
index 6ad59cb48f1a717699d2df19b725dec093218426..0871ed76523cec7a50d235c1ab070be8faae56a1 100644 (file)
@@ -117,7 +117,7 @@ public:
   l4_uint32_t read_rom() const { return _rom; }
   void write_rom(l4_uint32_t v);
 
-  int vbus_dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream &)
+  int vbus_dispatch(l4_umword_t, l4_uint32_t, L4::Ipc::Iostream &)
   { return -L4_ENOSYS; }
 
   Hw::Pci::If *hwf() const { return _hwf; }
@@ -134,7 +134,7 @@ public:
   bool match_hw_feature(const Hw::Dev_feature *f) const
   { return f == _hwf; }
 
-  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream&)
+  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc::Iostream&)
   { return -L4_ENOSYS; }
 
   void set_host(Device *d) { _host = d; }
index 2e9f4c351a6629e7739f1c518e1b7f932d52599b..2c35ca468983a7324646028ff6a082412b003eaa 100644 (file)
@@ -54,7 +54,7 @@ public:
   bool is_vpci_bridge() const { return true; }
 
   bool match_hw_feature(const Hw::Dev_feature*) const { return false; }
-  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc_iostream&)
+  int dispatch(l4_umword_t, l4_uint32_t, L4::Ipc::Iostream&)
   { return -L4_ENOSYS; }
 
 
index caee330a1e05ec9c0d0d6a8dcdaf888b65a8c7ce..aa20a553da28fd478af0bef99ece69db3144c4ae 100644 (file)
@@ -18,7 +18,7 @@ class VPci_root : public VDevice
 {
 public:
 
-  int vbus_dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios);
+  int vbus_dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
 
   explicit VPci_root() : VDevice() {}
 
@@ -30,16 +30,16 @@ public:
   }
 
 public:
-  int cfg_read(L4::Ipc_iostream &ios);
-  int cfg_write(L4::Ipc_iostream &ios);
-  int irq_enable(L4::Ipc_iostream &ios);
+  int cfg_read(L4::Ipc::Iostream &ios);
+  int cfg_write(L4::Ipc::Iostream &ios);
+  int irq_enable(L4::Ipc::Iostream &ios);
 };
 
 
 // IMPLEMENTATION --------------------------------------------------------
 
 int
-VPci_root::cfg_read(L4::Ipc_iostream &ios)
+VPci_root::cfg_read(L4::Ipc::Iostream &ios)
 {
   l4_uint32_t bus;
   l4_uint32_t devfn;
@@ -58,7 +58,7 @@ VPci_root::cfg_read(L4::Ipc_iostream &ios)
 }
 
 int
-VPci_root::irq_enable(L4::Ipc_iostream &ios)
+VPci_root::irq_enable(L4::Ipc::Iostream &ios)
 {
 #if 0
   l4_uint32_t bus;
@@ -87,7 +87,7 @@ VPci_root::irq_enable(L4::Ipc_iostream &ios)
 }
 
 int
-VPci_root::cfg_write(L4::Ipc_iostream &ios)
+VPci_root::cfg_write(L4::Ipc::Iostream &ios)
 {
   l4_uint32_t bus;
   l4_uint32_t devfn;
@@ -105,7 +105,7 @@ VPci_root::cfg_write(L4::Ipc_iostream &ios)
 }
 
 int
-VPci_root::vbus_dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
+VPci_root::vbus_dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
 {
   switch (func)
     {
index 538045022745438e1435bc5d35a99008a9406cbb..650e92677658e50df4f0f63f69ea0880cf6b957d 100644 (file)
@@ -22,7 +22,7 @@ public:
 
   explicit Pci_vroot();
 
-  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios);
 
   ~Pci_vroot() {}
 
@@ -36,9 +36,9 @@ private:
   Device *_host;
 
 public:
-  int cfg_read(L4::Ipc_iostream &ios);
-  int cfg_write(L4::Ipc_iostream &ios);
-  int irq_enable(L4::Ipc_iostream &ios);
+  int cfg_read(L4::Ipc::Iostream &ios);
+  int cfg_write(L4::Ipc::Iostream &ios);
+  int irq_enable(L4::Ipc::Iostream &ios);
   bool match_hw_feature(const Hw::Dev_feature*) const
   { return false; }
 };
@@ -68,7 +68,7 @@ Pci_vroot::Pci_vroot() : Pci_bridge()
 }
 
 int
-Pci_vroot::cfg_read(L4::Ipc_iostream &ios)
+Pci_vroot::cfg_read(L4::Ipc::Iostream &ios)
 {
   l4_uint32_t bus;
   l4_uint32_t devfn;
@@ -106,7 +106,7 @@ Pci_vroot::cfg_read(L4::Ipc_iostream &ios)
   return L4_EOK;
 }
 int
-Pci_vroot::irq_enable(L4::Ipc_iostream &ios)
+Pci_vroot::irq_enable(L4::Ipc::Iostream &ios)
 {
   l4_uint32_t bus;
   l4_uint32_t devfn;
@@ -144,7 +144,7 @@ Pci_vroot::irq_enable(L4::Ipc_iostream &ios)
 }
 
 int
-Pci_vroot::cfg_write(L4::Ipc_iostream &ios)
+Pci_vroot::cfg_write(L4::Ipc::Iostream &ios)
 {
   l4_uint32_t bus;
   l4_uint32_t devfn;
@@ -168,7 +168,7 @@ Pci_vroot::cfg_write(L4::Ipc_iostream &ios)
 }
 
 int
-Pci_vroot::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc_iostream &ios)
+Pci_vroot::dispatch(l4_umword_t, l4_uint32_t func, L4::Ipc::Iostream &ios)
 {
   switch (func)
     {
index c0333bab81fefa5dc272dfb7a9e4b695888276c3..1a12898fc83205211c7928603cb43a7c118ded16 100644 (file)
@@ -21,7 +21,7 @@
 long
 L4con::close() const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Close);
   return l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
 }
@@ -29,7 +29,7 @@ L4con::close() const throw()
 long
 L4con::pslim_fill(int x, int y, int w, int h, unsigned int color) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Pslim_fill);
   io << x << y << w << h << color;
   return l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
@@ -38,7 +38,7 @@ L4con::pslim_fill(int x, int y, int w, int h, unsigned int color) const throw()
 long
 L4con::pslim_copy(int x, int y, int w, int h, l4_int16_t dx, l4_int16_t dy) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Pslim_copy);
   io << x << y << w << h << dx << dy;
   return l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
@@ -48,10 +48,10 @@ long
 L4con::puts(const char *s, unsigned long len, short x, short y,
             unsigned int fg_color, unsigned int bg_color) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Puts);
   io << x << y << fg_color << bg_color
-     << L4::ipc_buf_cp_out(s, len);
+     << L4::Ipc::Buf_cp_out<const char>(s, len);
   return l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
 }
 
@@ -61,17 +61,17 @@ L4con::puts_scale(const char *s, unsigned long len,
                   unsigned int fg_color, unsigned int bg_color,
                   short scale_x, short scale_y) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Puts_scale);
   io << x << y << fg_color << bg_color << scale_x << scale_y
-     << L4::ipc_buf_cp_out(s, len);
+     << L4::Ipc::Buf_cp_out<const char>(s, len);
   return l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
 }
 
 long
 L4con::get_font_size(unsigned int *fn_w, unsigned int *fn_h) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4con_::Get_font_size);
   long r = l4_error(io.call(Framebuffer::cap(), L4con::Protocol::Vc));
   if (EXPECT_FALSE(r < 0))
index 842893f2e19f7a00cb2d2e13bda27e35c8369460..8fe80f29e174602a994271ace687bf2e48fb8eb6 100644 (file)
@@ -17,8 +17,6 @@
 #include <l4/sys/factory>
 #include <l4/sys/typeinfo_svr>
 #include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
 #include <l4/cxx/minmax>
 
 #include <l4/re/protocols>
@@ -61,7 +59,7 @@ class Vc : public L4Re::Util::Video::Goos_svr,
 public:
   explicit Vc();
   ~Vc();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   void setup_info(l4con_vc *vc);
   void reg_fbds(l4_cap_idx_t c);
@@ -69,15 +67,15 @@ public:
   int create_event();
 
   long close();
-  long pslim_fill(L4::Ipc_iostream &ios);
-  long pslim_copy(L4::Ipc_iostream &ios);
-  long puts(L4::Ipc_iostream &ios);
-  long puts_scale(L4::Ipc_iostream &ios);
-  long get_font_size(L4::Ipc_iostream &ios);
+  long pslim_fill(L4::Ipc::Iostream &ios);
+  long pslim_copy(L4::Ipc::Iostream &ios);
+  long puts(L4::Ipc::Iostream &ios);
+  long puts_scale(L4::Ipc::Iostream &ios);
+  long get_font_size(L4::Ipc::Iostream &ios);
 
   virtual int refresh(int x, int y, int w, int h);
 
-  long vc_dispatch(L4::Ipc_iostream &ios);
+  long vc_dispatch(L4::Ipc::Iostream &ios);
 
   static L4::Cap<void> rcv_cap() { return ::rcv_cap(); }
 private:
@@ -134,7 +132,7 @@ Vc::~Vc()
 }
 
 long
-Vc::pslim_fill(L4::Ipc_iostream &ios)
+Vc::pslim_fill(L4::Ipc::Iostream &ios)
 {
   l4con_pslim_rect_t r;
   l4con_pslim_color_t c;
@@ -151,7 +149,7 @@ Vc::pslim_fill(L4::Ipc_iostream &ios)
 }
 
 long
-Vc::pslim_copy(L4::Ipc_iostream &ios)
+Vc::pslim_copy(L4::Ipc::Iostream &ios)
 {
   l4con_pslim_rect_t r;
   int x, y, w, h;
@@ -168,7 +166,7 @@ Vc::pslim_copy(L4::Ipc_iostream &ios)
 }
 
 long
-Vc::puts(L4::Ipc_iostream &ios)
+Vc::puts(L4::Ipc::Iostream &ios)
 {
   char buf[150];
   char *s = 0;
@@ -179,7 +177,7 @@ Vc::puts(L4::Ipc_iostream &ios)
   l4con_pslim_color_t bg_color;
 
   ios >> x >> y >> fg_color >> bg_color
-      >> L4::ipc_buf_in(s, len);
+      >> L4::Ipc::Buf_in<char>(s, len);
 
   len = cxx::min<unsigned long>(len, sizeof(buf));
   memcpy(buf, s, len);
@@ -188,7 +186,7 @@ Vc::puts(L4::Ipc_iostream &ios)
 }
 
 long
-Vc::puts_scale(L4::Ipc_iostream &ios)
+Vc::puts_scale(L4::Ipc::Iostream &ios)
 {
   char buf[150];
   char *s = 0;
@@ -198,7 +196,7 @@ Vc::puts_scale(L4::Ipc_iostream &ios)
   l4con_pslim_color_t bg_color;
 
   ios >> x >> y >> fg_color >> bg_color >> scale_x >> scale_y
-      >> L4::ipc_buf_in(s, len);
+      >> L4::Ipc::Buf_in<char>(s, len);
 
   len = cxx::min<unsigned long>(len, sizeof(buf));
   memcpy(buf, s, len);
@@ -208,7 +206,7 @@ Vc::puts_scale(L4::Ipc_iostream &ios)
 }
 
 long
-Vc::get_font_size(L4::Ipc_iostream &ios)
+Vc::get_font_size(L4::Ipc::Iostream &ios)
 {
   int w = FONT_XRES, h = FONT_YRES;
   ios << w << h;
@@ -216,7 +214,7 @@ Vc::get_font_size(L4::Ipc_iostream &ios)
 }
 
 long
-Vc::vc_dispatch(L4::Ipc_iostream &ios)
+Vc::vc_dispatch(L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -245,7 +243,7 @@ Vc::vc_dispatch(L4::Ipc_iostream &ios)
 }
 
 int
-Vc::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Vc::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -320,11 +318,11 @@ Vc::reg_fbds(l4_cap_idx_t c)
 class Controller : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Controller::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Controller::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -371,10 +369,10 @@ public:
     con_registry.gc_run(500);
   }
 
-  void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
+  void setup_wait(L4::Ipc::Istream &istr, L4::Ipc_svr::Reply_mode)
   {
     istr.reset();
-    istr << L4::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap().cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 
index 85c0b4c66412993f26ac70c46e3c245ebd035dab..a3325092326a779b4f76239d093cd935203a7d40 100644 (file)
@@ -1,10 +1,9 @@
 PKGDIR ?= .
 L4DIR  ?= $(PKGDIR)/../..
 
-TARGET = lib include util lib_main
+TARGET = lib include util
 
 include $(L4DIR)/mk/subdir.mk
 
-lib_main:  include lib
 util:      include lib
 lib:       include
index 17243f25c9806a1a331333259947e9a8f25c7390..efb62c7179c272b448f3e0272f9c930061a2f9b0 100644 (file)
@@ -29,7 +29,7 @@
 #include <l4/cxx/ipc_stream>
 
 inline
-L4::Ipc_istream &operator >> (L4::Ipc_istream &s, L4Re::Dataspace::Stats &v)
+L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4Re::Dataspace::Stats &v)
 { s.get(v); return s; }
 
 namespace L4Re {
@@ -40,14 +40,14 @@ Dataspace::__map(unsigned long offset, unsigned char *size, unsigned long flags,
 {
   l4_addr_t spot = local_addr & ~(~0UL << l4_umword_t(*size));
   l4_addr_t base = local_addr & (~0UL << l4_umword_t(*size));
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Map) << offset << spot << flags;
-  io << L4::Rcv_fpage::mem(base, *size, 0);
+  io << L4::Ipc::Rcv_fpage::mem(base, *size, 0);
   long err = l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
   if (err < 0)
     return err;
 
-  L4::Snd_fpage fp;
+  L4::Ipc::Snd_fpage fp;
   io >> fp;
   *size = fp.rcv_order();
   return err;
@@ -107,7 +107,7 @@ Dataspace::map(l4_addr_t offset, unsigned long flags,
 long
 Dataspace::clear(unsigned long offset, unsigned long size) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Clear) << offset << size;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
   if (EXPECT_FALSE(err < 0))
@@ -121,7 +121,7 @@ Dataspace::clear(unsigned long offset, unsigned long size) const throw()
 int
 Dataspace::info(Stats *stats) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Stats);
   long err = l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
   if (EXPECT_FALSE(err < 0))
@@ -155,7 +155,7 @@ long
 Dataspace::copy_in(unsigned long dst_offs, L4::Cap<Dataspace> src,
                    unsigned long src_offs, unsigned long size) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Copy) << dst_offs << src_offs << size << src;
   return l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
 }
@@ -163,7 +163,7 @@ Dataspace::copy_in(unsigned long dst_offs, L4::Cap<Dataspace> src,
 long
 Dataspace::phys(l4_addr_t offset, l4_addr_t &phys_addr, l4_size_t &phys_size) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Phys) << offset;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
   if (EXPECT_FALSE(err < 0))
@@ -176,7 +176,7 @@ Dataspace::phys(l4_addr_t offset, l4_addr_t &phys_addr, l4_size_t &phys_size) co
 long
 Dataspace::allocate(l4_addr_t offset, l4_size_t size) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Allocate) << offset << size;
   return l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
 }
@@ -185,7 +185,7 @@ Dataspace::allocate(l4_addr_t offset, l4_size_t size) throw()
 long
 Dataspace::take() const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Take);
   return l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
 }
@@ -193,7 +193,7 @@ Dataspace::take() const throw()
 long
 Dataspace::release() const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Dataspace_::Release);
   return l4_error(io.call(cap(), L4Re::Protocol::Dataspace));
 }
index 51fe1dd74333d772b5d7631723e4ceb8a9ee6072..3fdb0f0496e32475b15f86c416aeadd096ec78d1 100644 (file)
@@ -47,7 +47,7 @@ Mem_alloc::alloc(unsigned long size,
 long
 Mem_alloc::free(L4::Cap<Dataspace> mem) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Mem_alloc_::Free) << mem;
   return l4_error(io.call(cap(), L4Re::Protocol::Mem_alloc));
 }
index b7aac55f31e9038c8712be694f4e609df33e7fd4..6e1d36edd7ccc2ac9a3826188049b693ed660cc5 100644 (file)
@@ -46,10 +46,10 @@ Namespace::_query(char const *name, unsigned len,
   L4::Cap<Namespace> ns(cap());
   while (res > 0)
     {
-      L4::Ipc_iostream io(l4_utcb());
+      L4::Ipc::Iostream io(l4_utcb());
       io << L4::Opcode(L4Re::Namespace_::Query)
-         << L4::ipc_buf_cp_out(n, res);
-      io << L4::Small_buf(target.cap(), local_id ? L4_RCV_ITEM_LOCAL_ID : 0);
+         << L4::Ipc::Buf_cp_out<const char>(n, res);
+      io << L4::Ipc::Small_buf(target.cap(), local_id ? L4_RCV_ITEM_LOCAL_ID : 0);
       l4_msgtag_t r = io.call(ns.cap(), L4Re::Protocol::Namespace);
       long err = l4_error(r);
 
@@ -60,10 +60,10 @@ Namespace::_query(char const *name, unsigned len,
       if (partly)
        {
          l4_umword_t dummy;
-         io >> dummy >> L4::ipc_buf_in(n, res);
+         io >> dummy >> L4::Ipc::Buf_in<char const>(n, res);
        }
 
-      L4::Snd_fpage cap;
+      L4::Ipc::Snd_fpage cap;
       io >> cap;
       if (cap.id_received())
        {
@@ -124,11 +124,11 @@ long
 Namespace::register_obj(char const *name, L4::Cap<void> const &o,
                         unsigned flags) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4Re::Namespace_::Register)
-     << flags << L4::ipc_buf_cp_out(name, strlen(name));
+     << flags << L4::Ipc::Buf_cp_out<char const>(name, strlen(name));
   if (o.is_valid())
-    io << L4::Snd_fpage(o.fpage(L4_FPAGE_RWX & flags));
+    io << L4::Ipc::Snd_fpage(o.fpage(L4_FPAGE_RWX & flags));
   l4_msgtag_t res = io.call(cap(), L4Re::Protocol::Namespace);
   return l4_error(res);
 }
@@ -136,9 +136,9 @@ Namespace::register_obj(char const *name, L4::Cap<void> const &o,
 long
 Namespace::unlink(char const *name) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4Re::Namespace_::Unlink)
-     << L4::ipc_buf_cp_out(name, strlen(name));
+     << L4::Ipc::Buf_cp_out<char const>(name, strlen(name));
   l4_msgtag_t res = io.call(cap(), L4Re::Protocol::Namespace);
   return l4_error(res);
 }
@@ -149,11 +149,11 @@ Namespace::link(char const *name, unsigned len,
                 char const *src_name, unsigned src_len,
                 unsigned flags) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(L4Re::Namespace_::Link)
-     << flags << L4::ipc_buf_cp_out(name, len)
-     << L4::ipc_buf_cp_out(src_name, src_len)
-     << L4::Snd_fpage(src_dir.fpage());
+     << flags << L4::Ipc::Buf_cp_out<char const>(name, len)
+     << L4::Ipc::Buf_cp_out<char const>(src_name, src_len)
+     << L4::Ipc::Snd_fpage(src_dir.fpage());
   l4_msgtag_t res = io.call(cap(), L4Re::Protocol::Namespace);
   return l4_error(res);
 }
index edc204732879c52e5446a7198e11c02da7b2ea71..f632247643358088c840524de83f645b42a8b98a 100644 (file)
@@ -41,7 +41,7 @@ long
 Rm::reserve_area(l4_addr_t *start, unsigned long size, unsigned flags,
                  unsigned char align) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Attach_area) << *start << size << flags << align;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Rm));
   if (EXPECT_FALSE(err < 0))
@@ -54,7 +54,7 @@ Rm::reserve_area(l4_addr_t *start, unsigned long size, unsigned flags,
 long
 Rm::free_area(l4_addr_t addr) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Detach_area) << addr;
   return l4_error(io.call(cap(), L4Re::Protocol::Rm));
 }
@@ -64,7 +64,7 @@ Rm::attach(l4_addr_t *start, unsigned long size, unsigned long flags,
            L4::Cap<Dataspace> mem, l4_addr_t offs,
            unsigned char align) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Attach) << l4_addr_t(*start) << size << flags
      << offs << align;
 
@@ -91,7 +91,7 @@ int
 Rm::_detach(l4_addr_t addr, unsigned long size, L4::Cap<Dataspace> *mem,
             L4::Cap<L4::Task> task, unsigned flags) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Detach) << addr << size << flags;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Rm));
   if (EXPECT_FALSE(err < 0))
@@ -143,7 +143,7 @@ int
 Rm::find(l4_addr_t *addr, unsigned long *size, unsigned long *offset,
          unsigned *flags, L4::Cap<Dataspace> *m) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Find) << *addr << *size;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Rm));
   if (EXPECT_FALSE(err < 0))
@@ -159,7 +159,7 @@ Rm::find(l4_addr_t *addr, unsigned long *size, unsigned long *offset,
 int
 Rm::get_regions(l4_addr_t start, Region **regions) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Get_regions) << start;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Rm));
   if (err > 0)
@@ -170,7 +170,7 @@ Rm::get_regions(l4_addr_t start, Region **regions) throw()
 int
 Rm::get_areas(l4_addr_t start, Area **areas) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Rm_::Get_areas) << start;
   long err = l4_error(io.call(cap(), L4Re::Protocol::Rm));
   if (err > 0)
index 48a6b7f359ded7f97513a9c09a051d6a14e681c6..f516d65dea6b6d371a757410ab0dcaf98b0061ca 100644 (file)
@@ -29,7 +29,7 @@
 int
 L4Re::Debug_obj::debug(unsigned long function) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << function;
   return l4_error(io.call(cap(), L4Re::Protocol::Debug));
 }
index bce1ff5bc7b3a5010f2e9c0519f1c42e6b4c6df5..0ba532ca17d2cebf3f92557ab2de236b0fd08c46 100644 (file)
@@ -33,16 +33,16 @@ using L4::Opcode;
 long
 Event::get_buffer(L4::Cap<Dataspace> ds) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Event_::Get);
-  io << L4::Small_buf(ds.cap());
+  io << L4::Ipc::Small_buf(ds.cap());
   return l4_error(io.call(cap(), L4Re::Protocol::Event));
 }
 
 long
 Event::get_num_streams() const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Event_::Get_num_streams);
   return l4_error(io.call(cap(), L4Re::Protocol::Event));
 }
@@ -50,7 +50,7 @@ Event::get_num_streams() const throw()
 long
 Event::get_stream_info(int idx, Event_stream_info *info) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Event_::Get_stream_info) << idx;
   long res = l4_error(io.call(cap(), L4Re::Protocol::Event));
   if (res < 0)
@@ -63,7 +63,7 @@ Event::get_stream_info(int idx, Event_stream_info *info) const throw()
 long
 Event::get_stream_info_for_id(l4_umword_t id, Event_stream_info *info) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Event_::Get_stream_info_for_id) << id;
   long res = l4_error(io.call(cap(), L4Re::Protocol::Event));
   if (res < 0)
@@ -77,7 +77,7 @@ long
 Event::get_axis_info(l4_umword_t id, unsigned naxes, unsigned *axis,
                      Event_absinfo *info) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Event_::Get_axis_info) << id << L4::Ipc::buf_cp_out(axis, naxes);
   long res = l4_error(io.call(cap(), L4Re::Protocol::Event));
   if (res < 0)
index 2df8184b8f94fe6724716c58e601335a21c02e8d..517ee48724b6327b4eb210054b9630b8210081a7 100644 (file)
@@ -34,7 +34,7 @@ namespace L4Re
 long
 Parent::signal(unsigned long sig, unsigned long val) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << L4::Opcode(Parent_::Signal) << sig << val;
   return l4_error(io.call(cap(), L4Re::Protocol::Parent));
 }
index 5f5072e1ed7aa0c300ccf34341415f7d4d4680de..5859a5be3e321c44112dc336fed1340a641bb4fc 100644 (file)
@@ -36,7 +36,7 @@ using L4::Opcode;
 int
 Goos::info(Info *info) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Info);
   long err = l4_error(io.call(cap(), L4Re::Protocol::Goos));
   if (EXPECT_FALSE(err < 0))
@@ -49,25 +49,25 @@ Goos::info(Info *info) const throw()
 int
 Goos::get_static_buffer(unsigned idx, L4::Cap<Dataspace> ds) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Get_buffer) << idx;
-  io << L4::Small_buf(ds.cap());
+  io << L4::Ipc::Small_buf(ds.cap());
   return l4_error(io.call(cap(), L4Re::Protocol::Goos));
 }
 
 int
 Goos::create_buffer(unsigned long size, L4::Cap<Dataspace> ds) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Create_buffer) << size;
-  io << L4::Small_buf(ds.cap());
+  io << L4::Ipc::Small_buf(ds.cap());
   return l4_error(io.call(cap(), L4Re::Protocol::Goos));
 }
 
 int
 Goos::delete_buffer(unsigned idx) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Delete_buffer) << idx;
   return l4_error(io.call(cap(), L4Re::Protocol::Goos));
 }
@@ -75,7 +75,7 @@ Goos::delete_buffer(unsigned idx) const throw()
 int
 Goos::create_view(View *view) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Create_view);
   int err = l4_error(io.call(cap(), L4Re::Protocol::Goos));
   if (err < 0)
@@ -88,7 +88,7 @@ Goos::create_view(View *view) const throw()
 int
 Goos::delete_view(View const &v) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Delete_view) << v._view_idx;
   return l4_error(io.call(cap(), L4Re::Protocol::Goos));
 }
@@ -96,7 +96,7 @@ Goos::delete_view(View const &v) const throw()
 int
 Goos::refresh(int x, int y, int w, int h) throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::Screen_refresh) << x << y << w << h;
   return l4_error(io.call(cap(), L4Re::Protocol::Goos));
 }
index d882200d92f54861aae047d00cf7d68a0e7dfff4..0edda32712e46f4dffeff7653b4a2baf15e0cc66 100644 (file)
@@ -36,7 +36,7 @@ using L4::Opcode;
 int
 View::info(Info *info) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::View_info) << _view_idx;
   long err = l4_error(io.call(_goos.cap(), L4Re::Protocol::Goos));
   if (EXPECT_FALSE(err < 0))
@@ -49,7 +49,7 @@ View::info(Info *info) const throw()
 int
 View::set_info(Info const &i) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::View_set_info) << _view_idx;
   io.put(i);
   return l4_error(io.call(_goos.cap(), L4Re::Protocol::Goos));
@@ -72,7 +72,7 @@ View::set_viewport(int scr_x, int scr_y, int w, int h,
 int
 View::stack(View const &pivot, bool behind) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::View_stack) << _view_idx << pivot.view_index() << behind;
   return l4_error(io.call(_goos.cap(), L4Re::Protocol::Goos));
 }
@@ -80,7 +80,7 @@ View::stack(View const &pivot, bool behind) const throw()
 int
 View::refresh(int x, int y, int w, int h) const throw()
 {
-  L4::Ipc_iostream io(l4_utcb());
+  L4::Ipc::Iostream io(l4_utcb());
   io << Opcode(Goos_::View_refresh) << _view_idx;
   io << x << y << w << h;
   return l4_error(io.call(_goos.cap(), L4Re::Protocol::Goos));
index 72b81bc5389a8e6c38d4b552986fdd998768fe7c..d9000fb64e9cfe0a69c2de4ce5b989bb17accfc7 100644 (file)
@@ -79,7 +79,7 @@ public:
    * \return 0 on success, <0 on error
    */
   int map(l4_addr_t offs, l4_addr_t spot, unsigned long flags,
-          l4_addr_t min, l4_addr_t max, L4::Snd_fpage &memory);
+          l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &memory);
 
   /**
    * \brief A hook that is called as the first operation in each map
index 91aebb50288c617d3016b4ef16f8ec1da03f9ffe..91f9e324bf1774fac671fe547dd9eaaec0e7de78 100644 (file)
@@ -39,7 +39,7 @@ protected:
 
 public:
   Event_svr() : Icu_svr(1, &_irq) {}
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   int get_num_streams() const { return 0; }
   int get_stream_info(int, L4Re::Event_stream_info *)
   { return -L4_EINVAL; }
@@ -53,7 +53,7 @@ public:
 template<typename SVR>
 inline
 int
-Event_svr<SVR>::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Event_svr<SVR>::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index 5e7086402c3ddc1477dc5dd765d6951354901151..167747fecbb4685c85d323687297c69be206d6f9 100644 (file)
@@ -20,13 +20,13 @@ private:
   ICU *this_icu() { return static_cast<ICU*>(this); }
 
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &iso);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &iso);
 };
 
 
 template<typename ICU>
 int
-Icu_svr<ICU>::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Icu_svr<ICU>::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   typedef typename ICU::Irq Irq;
   l4_msgtag_t tag;
@@ -41,7 +41,7 @@ Icu_svr<ICU>::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
     case L4_ICU_OP_BIND:
       {
        l4_umword_t irqnum;
-       L4::Snd_fpage irq_fp;
+       L4::Ipc::Snd_fpage irq_fp;
        ios >> irqnum >> irq_fp;
        Irq *irq = this_icu()->icu_get_irq(irqnum);
        if (!irq)
@@ -52,7 +52,7 @@ Icu_svr<ICU>::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
     case L4_ICU_OP_UNBIND:
       {
        l4_umword_t irqnum;
-       L4::Snd_fpage irq_fp;
+       L4::Ipc::Snd_fpage irq_fp;
        ios >> irqnum >> irq_fp;
        Irq *irq = this_icu()->icu_get_irq(irqnum);
        if (!irq)
@@ -108,12 +108,12 @@ public:
     void trigger() const
     { _cap->trigger(); }
 
-    int bind(ICU *, L4::Snd_fpage const &irq_fp);
-    int unbind(ICU *, L4::Snd_fpage const &irq_fp);
+    int bind(ICU *, L4::Ipc::Snd_fpage const &irq_fp);
+    int unbind(ICU *, L4::Ipc::Snd_fpage const &irq_fp);
     void mask(bool mask) const
     { (void)mask; }
 
-    int msi_info(L4::Ipc_ostream &) const
+    int msi_info(L4::Ipc::Ostream &) const
     { return -L4_EINVAL; }
 
     L4::Cap<L4::Irq> cap() const { return _cap.get(); }
@@ -150,7 +150,7 @@ public:
 
 template< typename ICU >
 int
-Icu_cap_array_svr<ICU>::Irq::bind(ICU *cfb, L4::Snd_fpage const &irq_fp)
+Icu_cap_array_svr<ICU>::Irq::bind(ICU *cfb, L4::Ipc::Snd_fpage const &irq_fp)
 {
   if (!irq_fp.cap_received())
     return -L4_EINVAL;
@@ -164,7 +164,7 @@ Icu_cap_array_svr<ICU>::Irq::bind(ICU *cfb, L4::Snd_fpage const &irq_fp)
 
 template< typename ICU >
 int
-Icu_cap_array_svr<ICU>::Irq::unbind(ICU *, L4::Snd_fpage const &/*irq_fp*/)
+Icu_cap_array_svr<ICU>::Irq::unbind(ICU *, L4::Ipc::Snd_fpage const &/*irq_fp*/)
 {
   L4Re::Env::env()->task()->unmap(_cap.fpage(L4_FPAGE_RWX), L4_FP_ALL_SPACES);
   _cap = L4::Cap<L4::Irq>::Invalid;
index 9c99ca92a22ce0bed8b1e37527ebde63069c4ae2..0068881f5995a8d8092fb1e4977d255761ce141e 100644 (file)
@@ -9,7 +9,7 @@
 namespace L4Re { namespace Util {
 
 template<typename KO>
-long handle_meta_request(L4::Ipc_iostream &ios)
+long handle_meta_request(L4::Ipc::Iostream &ios)
 { return L4::Util::handle_meta_request<KO>(ios); }
 
 }}
index f8eb13e2d796d8a5efc762526bc6856a737d33cd..7e9e73e7a670f4c57539f938d5e7ef700e06928a 100644 (file)
@@ -225,7 +225,7 @@ protected:
   // server support --------------------------------------------
   virtual Entry *alloc_dynamic_entry(Name const &n, unsigned flags) = 0;
   virtual void free_dynamic_entry(Entry *e) = 0;
-  virtual int get_capability(L4::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
+  virtual int get_capability(L4::Ipc::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
                              L4::Server_object **lo = 0) = 0;
   virtual int save_capability(L4::Cap<void> *cap) = 0;
   virtual void free_capability(L4::Cap<void> cap) = 0;
@@ -234,11 +234,11 @@ protected:
 
 public:
   // server interface ------------------------------------------
-  int query(L4::Ipc_iostream &ios, char *buffer, size_t blen);
-  int link_entry(L4::Ipc_iostream &ios, char *buffer, size_t blen);
-  int register_entry(L4::Ipc_iostream &ios, char *buffer, size_t blen);
-  int unlink_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios, char *buffer,
+  int query(L4::Ipc::Iostream &ios, char *buffer, size_t blen);
+  int link_entry(L4::Ipc::Iostream &ios, char *buffer, size_t blen);
+  int register_entry(L4::Ipc::Iostream &ios, char *buffer, size_t blen);
+  int unlink_entry(L4::Ipc::Iostream &ios, char *buffer, size_t max_len);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios, char *buffer,
                size_t blen);
 
 };
index a496a6b363a2042afaf2c54c23326afe80964ba5..a29aac931381b1ceead6f70fcc38ff7512143f62 100644 (file)
@@ -44,7 +44,7 @@ int region_map_server(RM *rm, IOS &ios)
            l4_addr_t start;
            unsigned long flags;
            l4_cap_idx_t client_cap_idx = L4_INVALID_CAP;
-           L4::Snd_fpage ds_cap;
+           L4::Ipc::Snd_fpage ds_cap;
            typename Rm_server::Dataspace ds = typename Rm_server::Dataspace();
            l4_addr_t offs;
            unsigned char align;
index 2cbcbb86c3dbf22909d86b870e6a5d4d4ddde606..e384ccbff7ba7a9ff698c09b439d096b9d30ead1 100644 (file)
@@ -52,7 +52,7 @@ public:
    *
    * \return error code.
    */
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   unsigned vcon_read(char *buf, unsigned size) throw();
   void vcon_write(const char *buf, unsigned size) throw();
@@ -71,7 +71,7 @@ private:
 
 template< typename SVR >
 int
-Vcon_svr<SVR>::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Vcon_svr<SVR>::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index fed46274bde452e5c8cbd4e53b340ca0f31b92b9..5498e4d2c9a21708fa8b9df67f28b55ffc3831f3 100644 (file)
@@ -85,7 +85,7 @@ public:
    *
    * \return error code.
    */
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   /**
    * \brief Initialize the view information structure of this object.
@@ -118,7 +118,7 @@ public:
 
 inline
 int
-Goos_svr::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Goos_svr::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index f0f3170a10923973cb560608cbc438214e0d8f67..26fdde389cb8364f5c1e8f2279cd2f43f5245811 100644 (file)
@@ -33,7 +33,7 @@
 
 #if 0
 inline
-L4::Ipc_ostream &operator << (L4::Ipc_ostream &s,
+L4::Ipc::Ostream &operator << (L4::Ipc_ostream &s,
                               L4Re::Dataspace::Stats const &st)
 { s.put(st); return s; }
 #endif
@@ -42,13 +42,13 @@ namespace L4Re { namespace Util {
 
 int
 Dataspace_svr::map(l4_addr_t offs, l4_addr_t hot_spot, unsigned long flags,
-                    l4_addr_t min, l4_addr_t max, L4::Snd_fpage &memory)
+                    l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &memory)
 {
   int err = map_hook(offs, flags, min, max);
   if (err < 0)
     return err;
 
-  memory = L4::Snd_fpage();
+  memory = L4::Ipc::Snd_fpage();
 
   offs     = l4_trunc_page(offs);
   hot_spot = l4_trunc_page(hot_spot);
@@ -95,7 +95,7 @@ Dataspace_svr::map(l4_addr_t offs, l4_addr_t hot_spot, unsigned long flags,
 
   l4_fpage_t fpage = l4_fpage(map_base, order, flags && is_writable() ?  L4_FPAGE_RWX : L4_FPAGE_RX);
   
-  memory = L4::Snd_fpage(fpage, hot_spot, _map_flags, _cache_flags);
+  memory = L4::Ipc::Snd_fpage(fpage, hot_spot, _map_flags, _cache_flags);
 
   return L4_EOK;
 }
@@ -129,7 +129,7 @@ Dataspace_svr::phys(l4_addr_t /*offset*/, l4_addr_t &/*phys_addr*/, l4_size_t &/
 }
 
 int
-Dataspace_svr::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Dataspace_svr::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
@@ -150,7 +150,7 @@ Dataspace_svr::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
        bool read_only = !is_writable() || !(obj & L4_FPAGE_X);
        l4_addr_t offset, spot;
        unsigned long flags;
-       L4::Snd_fpage fp;
+       L4::Ipc::Snd_fpage fp;
        ios >> offset >> spot >> flags;
 #if 0
        L4::cout << "MAPrq: " << L4::hex << offset << ", " << spot << ", "
@@ -198,7 +198,7 @@ Dataspace_svr::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
        l4_addr_t dst_offs;
        l4_addr_t src_offs;
        unsigned long sz;
-       L4::Snd_fpage src_cap;
+       L4::Ipc::Snd_fpage src_cap;
 
        ios >> dst_offs >> src_offs >> sz >> src_cap;
 
index 35a4c37d2229c5df4d27908bb5be056e4862711a..3fdfdc2997dbc2a24e3ef63cfb98908bc212b21a 100644 (file)
@@ -16,8 +16,6 @@
  * invalidate any other reasons why the executable file might be covered by
  * the GNU General Public License.
  */
-#include <l4/cxx/iostream>
-
 #include <l4/re/util/name_space_svr>
 #include <l4/re/util/debug>
 
@@ -113,11 +111,11 @@ Name_space::find_iter(Name const &pname) const
 
 
 int
-Name_space::query(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
+Name_space::query(L4::Ipc::Iostream &ios, char *buffer, size_t max_len)
 {
   char const *name = 0;
   unsigned long len = max_len;
-  ios >> L4::ipc_buf_in(name, len);
+  ios >> L4::Ipc::Buf_in<char const>(name, len);
 #if 1
   _dbg.printf("query: [%ld] '%.*s'\n", len, (int)len, name);
 #endif
@@ -159,14 +157,14 @@ Name_space::query(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
       if (part < len)
        {
          result |= L4Re::Namespace::Partly_resolved;
-         ios << (l4_umword_t)0 << L4::ipc_buf_cp_out(buffer, len - part - 1);
+         ios << (l4_umword_t)0 << L4::Ipc::Buf_cp_out<char>(buffer, len - part - 1);
        }
 
       unsigned flags = L4_FPAGE_RO;
       if (n->obj()->is_rw())     flags |= L4_FPAGE_RX;
       if (n->obj()->is_strong()) flags |= L4_FPAGE_RW;
 
-      ios << L4::Snd_fpage(n->obj()->cap().fpage(flags));
+      ios << L4::Ipc::Snd_fpage(n->obj()->cap().fpage(flags));
       _dbg.printf(" result = %lx flgs=%x strg=%d\n",
                   result, flags, (int)n->obj()->is_strong());
       return result;
@@ -221,14 +219,14 @@ Name_space::insert_entry(Name const &name, unsigned flags, Entry **e)
 }
 
 int
-Name_space::link_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
+Name_space::link_entry(L4::Ipc::Iostream &ios, char *buffer, size_t max_len)
 {
   char const *name = 0, *src_name = 0;
   unsigned long len, src_len;
   unsigned flags;
-  L4::Snd_fpage src_cap;
-  ios >> flags >> L4::ipc_buf_in(name, len)
-      >> L4::ipc_buf_in(src_name, src_len)
+  L4::Ipc::Snd_fpage src_cap;
+  ios >> flags >> L4::Ipc::Buf_in<char const>(name, len)
+      >> L4::Ipc::Buf_in<char const>(src_name, src_len)
       >> src_cap;
 
   L4::Cap<void> reg_cap(L4::Cap_base::No_init);
@@ -280,13 +278,13 @@ Name_space::link_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
 
 
 int
-Name_space::register_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
+Name_space::register_entry(L4::Ipc::Iostream &ios, char *buffer, size_t max_len)
 {
   char const *name = 0;
   unsigned long len;
   unsigned flags;
-  L4::Snd_fpage cap;
-  ios >> flags >> L4::ipc_buf_in(name, len);
+  L4::Ipc::Snd_fpage cap;
+  ios >> flags >> L4::Ipc::Buf_in<char const>(name, len);
 
   L4::Cap<void> reg_cap(L4_INVALID_CAP);
   l4_msgtag_t tag;
@@ -325,11 +323,11 @@ Name_space::register_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
 }
 
 int
-Name_space::unlink_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
+Name_space::unlink_entry(L4::Ipc::Iostream &ios, char *buffer, size_t max_len)
 {
   char const *name = 0;
   unsigned long len = max_len;
-  ios >> L4::ipc_buf_in(name, len);
+  ios >> L4::Ipc::Buf_in<char const>(name, len);
 #if 1
   _dbg.printf("unlink: [%ld] '%.*s'\n", len, (int)len, name);
 #endif
@@ -366,7 +364,7 @@ Name_space::unlink_entry(L4::Ipc_iostream &ios, char *buffer, size_t max_len)
 
 
 int
-Name_space::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios, char *buffer,
+Name_space::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios, char *buffer,
                      size_t max_len)
 {
   l4_msgtag_t tag;
index 89759de902755281463f00107d4066aa1c97eb72..a7e8c8b185c115c60d38ff4981a48fa2585c70f6 100644 (file)
@@ -1,2 +1,3 @@
-requires: stdlibs libloader
+requires: l4re-util libc_minimal libsupc++_minimal libloader
+          libc_be_minimal_log_io libc_minimal_l4re
 maintainer: warg@os.inf.tu-dresden.de
index 37d0d94dbe54d35eea68e7656103998c31fa77a7..3ff38721d2301098689e225155ba11bd067fb5b1 100644 (file)
@@ -20,8 +20,8 @@ DEFINES += -DL4_CXX_NO_EXCEPTION_BACKTRACE
 
 MMAP_BACKEND   :=
 
-REQUIRES_LIBS  := libc_be_minimal_log_io cxx_io cxx_libc_io libc l4re \
-                  l4re-util libsupc++ l4re-main libloader
+REQUIRES_LIBS  := libc_be_minimal_log_io cxx_io cxx_libc_io libc_minimal l4re \
+                  l4re-util libsupc++_minimal libloader libc_minimal_l4re
 
 include $(L4DIR)/mk/prog.mk
 
index 1ed38c0e3a175ccf9a29e14f00727d4eab06d9d4..006a521f28df6a5f702860d21ead2bf2ea046a33 100644 (file)
@@ -24,7 +24,7 @@
 static Dbg dbg(Dbg::Server, "svr");
 
 int
-Dispatcher::handle_exception(L4::Ipc_iostream &ios)
+Dispatcher::handle_exception(L4::Ipc::Iostream &ios)
 {
   l4_exc_regs_t u = *l4_utcb_exc();
 
@@ -34,7 +34,7 @@ Dispatcher::handle_exception(L4::Ipc_iostream &ios)
 }
 
 int
-Dispatcher::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Dispatcher::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
index 46ce63f727339c874af175f4a5bf86b73573d292..f42a681a6c45f673972adc2fa74ff7cca7c22cb8 100644 (file)
@@ -16,9 +16,9 @@
 class Dispatcher : public L4::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 private:
-  int handle_callback(L4::Ipc_iostream &ios);
-  int handle_exception(L4::Ipc_iostream &ios);
+  int handle_callback(L4::Ipc::Iostream &ios);
+  int handle_exception(L4::Ipc::Iostream &ios);
 };
index 36fa2f38c8e6e6a83a8e74a33107dbe20fddc45c..508157e58a03bf77c5f528d7228056c293c5417d 100644 (file)
@@ -55,7 +55,7 @@ public:
   static void setup_wait(L4::Ipc::Istream &istr, bool)
   {
     istr.reset();
-    istr << L4::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 };
index 0b6f79bbcd36e2a088f88d48a0b9a221b0d0d232..233c0b2c2153ea07a91a97445453297ee1d8f535 100644 (file)
@@ -78,9 +78,9 @@ Region_ops::map(Region_handler const *h, l4_addr_t local_adr,
 
   if (h->flags() & Rm::Pager)
     {
-      L4::Ipc_iostream io(l4_utcb());
+      L4::Ipc::Iostream io(l4_utcb());
       io << (local_adr | (writable ? 2 : 0)) << -3UL;
-      io << L4::Rcv_fpage::mem(0, 32, 0);
+      io << L4::Ipc::Rcv_fpage::mem(0, L4_WHOLE_ADDRESS_SPACE, 0);
       io.call(h->memory().cap(), L4_PROTO_PAGE_FAULT);
       return L4_EOK;
     }
@@ -153,7 +153,7 @@ Region_ops::release(Region_handler const * /*h*/)
 
 template<typename T>
 inline
-T extract(L4::Ipc_istream &s)
+T extract(L4::Ipc::Istream &s)
 { T t; s >> t; return t; }
 
 void
@@ -179,7 +179,7 @@ class Rm_server
 public:
   typedef L4::Cap<L4Re::Dataspace> Dataspace;
   enum { Have_find = true };
-  static int validate_ds(L4::Snd_fpage const &ds_cap,
+  static int validate_ds(L4::Ipc::Snd_fpage const &ds_cap,
                          unsigned, L4::Cap<L4Re::Dataspace> *ds)
   {
     // if no cap was sent then the region will be reserved
@@ -198,11 +198,11 @@ public:
 };
 
 int
-Region_map::handle_rm_request(L4::Ipc_iostream &ios)
+Region_map::handle_rm_request(L4::Ipc::Iostream &ios)
 {
   return L4Re::Util::region_map_server<Rm_server>(this, ios);
 }
 
 int
-Region_map::handle_pagefault(L4::Ipc_iostream &ios)
+Region_map::handle_pagefault(L4::Ipc::Iostream &ios)
 { return L4Re::Util::region_pf_handler<Dbg>(this, ios); }
index 74e5d34122d8b7f72824d5e71c58a25bf963299e..e6f350072e7deefed732c92f1984eb1a701e1d4b 100644 (file)
@@ -58,16 +58,16 @@ private:
 
 public:
   Region_map();
-  //void setup_wait(L4::Ipc_istream &istr);
-  int handle_pagefault(L4::Ipc_iostream &ios);
-  int handle_rm_request(L4::Ipc_iostream &ios);
+  //void setup_wait(L4::Ipc::Istream &istr);
+  int handle_pagefault(L4::Ipc::Iostream &ios);
+  int handle_rm_request(L4::Ipc::Iostream &ios);
   virtual ~Region_map() {}
 
   void init();
 
   void debug_dump(unsigned long function) const;
 private:
-  int reply_err(L4::Ipc_iostream &ios);
+  int reply_err(L4::Ipc::Iostream &ios);
 };
 
 
index 0acbd0ae9b06c349cceb28e2cf540206f143bb35..1dd9d653ab61ee1fb488f28b66e9f6989b0fdb09 100644 (file)
 #define L4_STICKY(x)   __attribute__((used)) x         ///< Mark symbol sticky (even not there) \hideinitializer
 /* The deprecated attribute is available with 3.1 and higher (3.3 as here
  * is ok for us */
-#define L4_DEPRECATED  __attribute__((deprecated))     ///< Mark symbol deprecated. \hideinitializer
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) || __GNUC__ >= 5
+# define L4_DEPRECATED(s) __attribute__((deprecated(s)))     ///< Mark symbol deprecated. \hideinitializer
+# else
+# define L4_DEPRECATED(s) __attribute__((deprecated))     ///< Mark symbol deprecated. \hideinitializer
+# endif
 #else
 /* The "used" attribute is not available with older gcc versions so simply
  * make sure that gcc doesn't warn about unused functions. */
 #define L4_STICKY(x)   __attribute__((unused)) x       ///< Mark symbol sticky (even not there).
-#define L4_DEPRECATED                                   ///< Mark symbol deprecated
+#define L4_DEPRECATED(s)                                ///< Mark symbol deprecated
 #endif
 
 #ifndef __GXX_EXPERIMENTAL_CXX0X__
index 2a768fcd61f304c3bf6083f9f4a8595de9e0fea3..b80783502af95f681b6a1d72df1aba6a1b51aa72 100644 (file)
@@ -72,13 +72,26 @@ public:
   { return l4_debugger_kobj_to_id_u(cap(), kobjp, utcb); }
 
   /**
-   * \copydoc l4_debugger_switch_log()
+   * \copydoc l4_debugger_query_log_typeid()
    * \note the \a cap argument is the implicit \a this pointer.
    */
-  unsigned query_log_typeid(const char *name, unsigned idx,
-                            l4_utcb_t *utcb = l4_utcb()) throw()
+  int query_log_typeid(const char *name, unsigned idx,
+                      l4_utcb_t *utcb = l4_utcb()) throw()
   { return l4_debugger_query_log_typeid_u(cap(), name, idx, utcb); }
 
+  /**
+   * \copydoc l4_debugger_query_log_name()
+   * \note the \a cap argument is the implicit \a this pointer.
+   */
+  int query_log_name(unsigned idx,
+                     char *name, unsigned namelen,
+                     char *shortname, unsigned shortnamelen,
+                     l4_utcb_t *utcb = l4_utcb()) throw()
+  {
+    return l4_debugger_query_log_name_u(cap(), idx, name, namelen,
+                                        shortname, shortnamelen, utcb);
+  }
+
   /**
    * \copydoc l4_debugger_switch_log()
    * \note the \a cap argument is the implicit \a this pointer.
index 610322f6c3b890293381a26f450d8f68507bd4ef..c53499e51e1ea35ac966b2143d212b828bb42b97 100644 (file)
@@ -99,25 +99,53 @@ l4_debugger_kobj_to_id_u(l4_cap_idx_t cap, l4_addr_t kobjp, l4_utcb_t *utcb) L4_
 /**
  * \brief Query the log-id for a log type
  *
- * \param cap    Capability
- * \param  name  Name to query for.
- * \param  idx   Idx to start searching, start with 0
+ * \param cap    Debugger capability
+ * \param name   Name to query for.
+ * \param idx    Idx to start searching, start with 0
  *
- * \return ID, ~0U on error or no valid log name.
+ * \return positive ID, or negative error code
  *
  * This is a debugging factility, the call might be invalid.
  */
-L4_INLINE unsigned
+L4_INLINE int
 l4_debugger_query_log_typeid(l4_cap_idx_t cap, const char *name,
                              unsigned idx) L4_NOTHROW;
 
 /**
  * \internal
  */
-L4_INLINE unsigned
+L4_INLINE int
 l4_debugger_query_log_typeid_u(l4_cap_idx_t cap, const char *name,
                                unsigned idx, l4_utcb_t *utcb) L4_NOTHROW;
 
+/**
+ * \brief Query the name of a log type given the ID
+ *
+ * \param cap          Debugger capability.
+ * \param idx          ID to query.
+ * \param name         Buffer to copy name to.
+ * \param namelen      Buffer length of name.
+ * \param shortname    Buffer to copy short-name to.
+ * \param shortnamelen Buffer length of short-name.
+ *
+ * \return 0 for success, ~0U in case of error
+ *
+ * This is a debugging factility, the call might be invalid.
+ */
+L4_INLINE int
+l4_debugger_query_log_name(l4_cap_idx_t cap, unsigned idx,
+                           char *name, unsigned namelen,
+                           char *shortname, unsigned shortnamelen) L4_NOTHROW;
+
+/**
+ * \internal
+ */
+L4_INLINE int
+l4_debugger_query_log_name_u(l4_cap_idx_t cap, unsigned idx,
+                             char *name, unsigned namelen,
+                             char *shortname, unsigned shortnamelen,
+                             l4_utcb_t *utcb) L4_NOTHROW;
+
 /**
  * \brief Set or unset log.
  */
@@ -140,6 +168,7 @@ enum
   L4_DEBUGGER_QUERY_LOG_TYPEID_OP = 3UL,
   L4_DEBUGGER_SWITCH_LOG_OP       = 4UL,
   L4_DEBUGGER_NAME_GET_OP         = 5UL,
+  L4_DEBUGGER_QUERY_LOG_NAME_OP   = 6UL,
 };
 
 enum
@@ -187,23 +216,47 @@ l4_debugger_kobj_to_id_u(l4_cap_idx_t cap, l4_addr_t kobjp, l4_utcb_t *utcb) L4_
   return l4_utcb_mr_u(utcb)->mr[0];
 }
 
-L4_INLINE unsigned
+L4_INLINE int
 l4_debugger_query_log_typeid_u(l4_cap_idx_t cap, const char *name,
                                unsigned idx,
                                l4_utcb_t *utcb) L4_NOTHROW
 {
   unsigned l;
+  int e;
   l4_utcb_mr_u(utcb)->mr[0] = L4_DEBUGGER_QUERY_LOG_TYPEID_OP;
   l4_utcb_mr_u(utcb)->mr[1] = idx;
   l = __builtin_strlen(name);
   l = l > 31 ? 31 : l;
   __builtin_strncpy((char *)&l4_utcb_mr_u(utcb)->mr[2], name, 31);
   l = (l + 1 + sizeof(l4_umword_t) - 1) / sizeof(l4_umword_t);
-  if (l4_error_u(l4_invoke_debugger(cap, l4_msgtag(0, 2 + l, 0, 0), utcb), utcb))
-    return ~0U;
+  e = l4_error_u(l4_invoke_debugger(cap, l4_msgtag(0, 2 + l, 0, 0), utcb), utcb);
+  if (e < 0)
+    return e;
   return l4_utcb_mr_u(utcb)->mr[0];
 }
 
+L4_INLINE int
+l4_debugger_query_log_name_u(l4_cap_idx_t cap, unsigned idx,
+                             char *name, unsigned namelen,
+                             char *shortname, unsigned shortnamelen,
+                             l4_utcb_t *utcb) L4_NOTHROW
+{
+  int e;
+  char *n;
+  l4_utcb_mr_u(utcb)->mr[0] = L4_DEBUGGER_QUERY_LOG_NAME_OP;
+  l4_utcb_mr_u(utcb)->mr[1] = idx;
+  e = l4_error_u(l4_invoke_debugger(cap, l4_msgtag(0, 2, 0, 0), utcb), utcb);
+  if (e < 0)
+    return e;
+  n = (char *)&l4_utcb_mr_u(utcb)->mr[0];
+  __builtin_strncpy(name, n, namelen);
+  name[namelen - 1] = 0;
+  __builtin_strncpy(shortname, n + __builtin_strlen(n) + 1, shortnamelen);
+  shortname[shortnamelen - 1] = 0;
+  return 0;
+}
+
+
 L4_INLINE l4_msgtag_t
 l4_debugger_switch_log_u(l4_cap_idx_t cap, const char *name, int on_off,
                          l4_utcb_t *utcb) L4_NOTHROW
@@ -252,13 +305,22 @@ l4_debugger_kobj_to_id(l4_cap_idx_t cap, l4_addr_t kobjp) L4_NOTHROW
   return l4_debugger_kobj_to_id_u(cap, kobjp, l4_utcb());
 }
 
-L4_INLINE unsigned
+L4_INLINE int
 l4_debugger_query_log_typeid(l4_cap_idx_t cap, const char *name,
                              unsigned idx) L4_NOTHROW
 {
   return l4_debugger_query_log_typeid_u(cap, name, idx, l4_utcb());
 }
 
+L4_INLINE int
+l4_debugger_query_log_name(l4_cap_idx_t cap, unsigned idx,
+                           char *name, unsigned namelen,
+                           char *shortname, unsigned shortnamelen) L4_NOTHROW
+{
+  return l4_debugger_query_log_name_u(cap, idx, name, namelen,
+                                      shortname, shortnamelen, l4_utcb());
+}
+
 L4_INLINE l4_msgtag_t
 l4_debugger_switch_log(l4_cap_idx_t cap, const char *name,
                        int on_off) L4_NOTHROW
index 6d700c9768dfd6d4a49cad0e10f8130a96afb536..50726253d8fca2285a73d745453b56d1910ed205 100644 (file)
@@ -29,7 +29,7 @@
 namespace L4 { namespace Util {
 
 template<typename KO>
-long handle_meta_request(L4::Ipc_iostream &ios)
+long handle_meta_request(L4::Ipc::Iostream &ios)
 {
   l4_umword_t op;
   ios >> op;
index bffa3c3b639d2b53352baa678343fa78cca2122a..d61161a1fd9ecf77649de997f1cc836444672b13 100644 (file)
 #  define l4util_idstr(tid)    (tid >> L4_CAP_SHIFT)
 #endif
 
-/* generate printf string of the task number of an L4 thread id */
-//#ifndef l4util_idtskstr
-//#  define l4util_idtskfmt      "#%X"
-//#  define l4util_idtskstr(tid) (tid).id.task
-//#endif
-
 #endif /* !_L4UTIL__ARCH_AMD64__L4F__L4_MACROS_H */
index 4a8318d2d51aa3881dae207c74becf7477263b7d..a431c9ac80d3779d881bfe927a6c1d15a18c3857 100644 (file)
 #  define l4util_idstr(tid)    (tid >> L4_CAP_SHIFT)
 #endif
 
-/* generate printf string of the task number of an L4 thread id */
-//#ifndef l4util_idtskstr
-//#  define l4util_idtskfmt      "#%x"
-//#  define l4util_idtskstr(tid) (tid).id.task
-//#endif
-
 #endif /* !_L4UTIL__ARCH_ARM__L4F__L4_MACROS_H */
index 77c799e69bd485b2942eb1c8d2daf26dc5734991..6ae172b3d164c68bc4bc840700892c77d61da3c5 100644 (file)
 #  define l4util_idstr(tid)    (tid >> L4_CAP_SHIFT)
 #endif
 
-/* generate printf string of the task number of an L4 thread id */
-//#ifndef l4util_idtskstr
-//#  define l4util_idtskfmt      "#%x"
-//#  define l4util_idtskstr(tid) tid
-//#endif
-
 #endif /* !_L4UTIL__ARCH_X86__L4F__L4_MACROS_H */
index 2622b91e59760c16a40da14d71be0e07fd5f6e07..235130653dc97f4c2bc4c928371597d13dbec359 100644 (file)
@@ -39,7 +39,7 @@ EXTERN_C_BEGIN
  *  base-64-encode string \a infile adding padding as per spec
  */
 L4_CV void base64_encode( const char *infile, unsigned int in_size, char **outfile);
+
 /*!
  * \brief decode base-64-encoded string \a infile
  * \internal
index d93e2266c99a1068f741f6a1be37e68f4753cc58..15bda230c4fa341b2f7b77dcc51174abb20b6502 100644 (file)
@@ -23,7 +23,7 @@
 
 EXTERN_C_BEGIN
 
-/** 
+/**
  * \defgroup l4util_random Random number support
  * \ingroup l4util_api
  */
@@ -31,7 +31,7 @@ EXTERN_C_BEGIN
 /**
  * \brief Deliver next random number
  * \ingroup l4util_random
- * 
+ *
  * \return A new random number
  */
 L4_CV l4_uint32_t
@@ -40,7 +40,7 @@ l4util_rand(void);
 /**
  * \brief Initialize random number generator
  * \ingroup l4util_random
- * 
+ *
  * \param seed Value to initialize
  */
 L4_CV void
index c8a05665964d3bb82cc33fa829173201a56d64e0..d15bf12f3270243bb04b3d1184850b0d04439351 100644 (file)
@@ -52,12 +52,6 @@ map_remove(slmap_t* list, slmap_t* entry);
 L4_CV void
 map_free_entry(slmap_t** entry);
 
-L4_CV static inline void
-map_free(slmap_t** list);
-
-L4_CV static inline unsigned char
-map_is_empty(slmap_t* list);
-
 L4_CV slmap_t*
 map_get_at(slmap_t* list, int n);
 
@@ -67,9 +61,6 @@ map_add(slmap_t* list, slmap_t* new_entry);
 L4_CV void
 map_insert_after(slmap_t* after, slmap_t* new_entry);
 
-L4_CV static inline int
-map_elements(slmap_t* list);
-
 L4_CV slmap_t*
 map_find(slmap_t* list, void* key, unsigned key_size);
 
index ccf6f696b37aad57bbbad49cd3992ec27a0f4367..0f8bb7e02b7ae91452eae60bab7951cd99af6043 100644 (file)
@@ -32,7 +32,7 @@ apic_show_register_block(unsigned int beg, unsigned int len)
   outstring("\r\n");
 }
 
-void
+L4_CV void
 apic_show_registers(void)
 {
   if (!apic_map_base)
@@ -47,23 +47,23 @@ apic_show_registers(void)
   apic_show_register_block(0x380, 0x10);  // Initial Count Register
 }
 
-void
+L4_CV void
 apic_timer_set_divisor(int newdiv)
 {
   int i;
   int div = -1;
   int divval = newdiv;
   unsigned long tmp_value;
-    
-  static int divisor_tab[8] = 
+
+  static int divisor_tab[8] =
     {
       APIC_TDR_DIV_1,  APIC_TDR_DIV_2,  APIC_TDR_DIV_4,  APIC_TDR_DIV_8,
-      APIC_TDR_DIV_16, APIC_TDR_DIV_32, APIC_TDR_DIV_64, APIC_TDR_DIV_128 
+      APIC_TDR_DIV_16, APIC_TDR_DIV_32, APIC_TDR_DIV_64, APIC_TDR_DIV_128
     };
 
   if (!apic_map_base)
     return;
-    
+
   for (i=0; i<8; i++)
     {
       if (divval & 1)
@@ -77,7 +77,7 @@ apic_timer_set_divisor(int newdiv)
        }
       divval >>= 1;
     }
-    
+
   if (div != -1)
     {
       apic_timer_divisor = newdiv;
@@ -89,7 +89,7 @@ apic_timer_set_divisor(int newdiv)
 }
 
 
-int
+L4_CV int
 apic_check_working(void)
 {
 #define CLOCK_TICK_RATE 1193180  /* i8254 ticks per second */
@@ -100,25 +100,25 @@ apic_check_working(void)
 
   if (!apic_map_base)
     return 0;
-    
+
   apic_timer_disable_irq();
   apic_timer_set_divisor(1);
   apic_timer_write(1000000000);
 
   /* Set the Gate high, disable speaker */
   l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
-  
+
   l4util_out8(0xb0, 0x43);  /* binary, mode 0, LSB/MSB, Ch 2 */
   l4util_out8(calibrate_latch & 0xff, 0x42); /* LSB of count */
   l4util_out8(calibrate_latch >> 8,   0x42); /* MSB of count */
 
   tt1=apic_timer_read();
   count = 0;
-  do 
+  do
     {
       count++;
     } while ((l4util_in8(0x61) & 0x20) == 0);
-    
+
   tt2=apic_timer_read();
   return (tt1-tt2) != 0;
 }
@@ -127,7 +127,7 @@ apic_check_working(void)
 /* activate APIC after activating by MSR was successful *
  * see "Intel Architecture Software Developer's Manual, *
  *      Volume 3: System Programming Guide, Appendix E" */
-void
+L4_CV void
 apic_activate_by_io(void)
 {
   char old_21, old_A1;
@@ -135,7 +135,7 @@ apic_activate_by_io(void)
   l4_umword_t flags;
 
   /* mask 8259 interrupts */
-  old_21 = l4util_in8(0x21); 
+  old_21 = l4util_in8(0x21);
   l4util_out8(0xff, 0x21);
   old_A1 = l4util_in8(0xA1);
   l4util_out8(0xff, 0xA1);
@@ -150,13 +150,13 @@ apic_activate_by_io(void)
   tmp_val &= 0xfffe58ff;
   tmp_val |= 0x00000700;
   apic_write(APIC_LVT0, tmp_val);
-    
+
   /* set LINT1 to NMI, edge triggered */
   tmp_val = apic_read(APIC_LVT1);
   tmp_val &= 0xfffe58ff;
   tmp_val |= 0x00000400;
   apic_write(APIC_LVT1, tmp_val);
-    
+
   /* unmask 8259 interrupts */
   l4util_flags_restore(&flags);
   l4util_out8(old_A1, 0xA1);
@@ -166,19 +166,19 @@ apic_activate_by_io(void)
 /*
  * Return APIC clocks per ms
  */
-unsigned long
+L4_CV unsigned long
 l4_calibrate_apic (void)
 {
   unsigned int calibrate_latch = (CLOCK_TICK_RATE / 20); /* 50 ms */
   unsigned int calibrate_time  = 50;                     /* 50 ms */
-  
+
   if (!apic_map_base)
     return 0;
-  
+
   apic_timer_disable_irq();
   apic_timer_set_divisor(apic_timer_divisor);
   apic_timer_write(1000000000);
-    
+
   /* Set the Gate high, disable speaker */
   l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
 
@@ -204,11 +204,11 @@ l4_calibrate_apic (void)
       /* Error: ECTCNEVERSET */
       if (count <= 1)
        goto bad_ctc;
-        
+
       /* Error: ECPUTOOSLOW */
       if (result <= calibrate_time)
        goto bad_ctc;
-        
+
       __asm__ ("divl %1"
              :"=a" (result)
              :"r" (calibrate_time),
index 658815ae0537d0437359e5a0f4fb0bc4651693fb..3acf0aa2bc18736018937f044388d830c7c83a28 100644 (file)
@@ -38,7 +38,7 @@ muldiv (l4_uint32_t a, l4_uint32_t mul, l4_uint32_t div)
  * Note, l4_tsc_init(L4_TSC_INIT_CALIBRATE) needs to have
  * I/O ports 0x20, 0x42, 0x43 and 0x61
  */
-l4_uint32_t
+L4_CV l4_uint32_t
 l4_tsc_init (int constraint, l4_kernel_info_t *kip)
 {
   l4_scaler_tsc_linux = 0;
@@ -134,7 +134,7 @@ bad_ctc:
   return 0;
 }
 
-l4_uint32_t
+L4_CV l4_uint32_t
 l4_get_hz (void)
 {
   if (!l4_scaler_tsc_to_ns)
index 7b5d7db1c7441a48c9fa1dbcb4db1d3c7d29c958..b1b0168f1748d67d9d3fe98582f3c84775049a23 100644 (file)
@@ -23,10 +23,10 @@ static void spin_gen(void*addr,int x,int y){
 *  l4_spin_vga() - the same for vga.                                        *
 *                                                                           *
 ****************************************************************************/
-void l4_spin(int x,int y){
+L4_CV void l4_spin(int x,int y){
   spin_gen((void*)0xb0000, x, y);
 }
-void l4_spin_vga(int x, int y){
+L4_CV void l4_spin_vga(int x, int y){
   spin_gen((void*)0xb8000, x, y);
 }
 
@@ -59,9 +59,9 @@ static void spin_n_text_gen(void*addr, int x,int y, int len, const char*s){
 *  l4_spin_n_text_vga() - same for vga.                                     *
 *                                                                           *
 ****************************************************************************/
-void l4_spin_n_text(int x,int y, int len, const char*s){
+L4_CV void l4_spin_n_text(int x,int y, int len, const char*s){
   spin_n_text_gen((void*)0xb0000, x, y, len, s);
 }
-void l4_spin_n_text_vga(int x,int y, int len, const char*s){
+L4_CV void l4_spin_n_text_vga(int x,int y, int len, const char*s){
   spin_n_text_gen((void*)0xb8000, x, y, len, s);
 }
index d0192a489e925f05efe1a7f7df8cfdba67079858..5aa79bcb1e8359097ec7e05df5c0a00bab894698 100644 (file)
@@ -21,7 +21,7 @@
 
 /*!\brief Initialize allocator array
  */
-l4util_alloc_t *l4util_alloc_init(int count, int base){
+L4_CV l4util_alloc_t *l4util_alloc_init(int count, int base){
     l4util_alloc_t *alloc;
     if((alloc=malloc(sizeof(l4util_alloc_t)))==0) return 0;
     if((alloc->bits = malloc((count+(L4UTIL_ALLOC_BITS_SIZE-1))/8))==0){
@@ -40,7 +40,7 @@ l4util_alloc_t *l4util_alloc_init(int count, int base){
  * \retval 0   not avail
  * \retval 1   avail
  */
-int l4util_alloc_avail(l4util_alloc_t *alloc, int elem){
+L4_CV int l4util_alloc_avail(l4util_alloc_t *alloc, int elem){
     if(elem<alloc->base || elem >= alloc->base+alloc->count) return 0;
     elem-=alloc->base;
     return !l4util_test_bit(elem&(L4UTIL_ALLOC_BITS_SIZE-1),
@@ -53,7 +53,7 @@ int l4util_alloc_avail(l4util_alloc_t *alloc, int elem){
  * \retval 0           OK
  * \retval 1           was occupied already or out of bound
  */
-int l4util_alloc_occupy(l4util_alloc_t *alloc, int elem){
+L4_CV int l4util_alloc_occupy(l4util_alloc_t *alloc, int elem){
     if(elem<alloc->base || elem >= alloc->base+alloc->count) return 1;
     elem-=alloc->base;
     return l4util_test_and_set_bit(elem&(L4UTIL_ALLOC_BITS_SIZE-1),
@@ -65,7 +65,7 @@ int l4util_alloc_occupy(l4util_alloc_t *alloc, int elem){
  * \retval >0          element
  * \retval -1          Error, none free
  */
-int l4util_alloc_alloc(l4util_alloc_t *alloc){
+L4_CV int l4util_alloc_alloc(l4util_alloc_t *alloc){
     int elem=alloc->next_elem;
 
     while(l4util_alloc_occupy(alloc, elem)){
@@ -84,7 +84,7 @@ int l4util_alloc_alloc(l4util_alloc_t *alloc){
  * \retval 0           OK
  * \retval 1           was not occupied or out of bound
  */
-int l4util_alloc_free(l4util_alloc_t *alloc, int elem){
+L4_CV int l4util_alloc_free(l4util_alloc_t *alloc, int elem){
     if(elem < alloc->base || elem >= alloc->base+alloc->count){
        return 1;
     }
index 3f0c00b22ddbddcd223b6f6e7595840bad91825c..b1388972958908b14a2d698848c9f4cf5ef3d978 100644 (file)
@@ -259,7 +259,7 @@ static void base64_decodeblock(unsigned char in[4], unsigned char out[3]);
 
 // implementation of public functions
 
-void base64_encode( const char *infile, unsigned int in_size, char **outfile)
+L4_CV void base64_encode( const char *infile, unsigned int in_size, char **outfile)
 {
   unsigned char in[3], out[4];
   int i, len = 0;
@@ -294,7 +294,7 @@ void base64_encode( const char *infile, unsigned int in_size, char **outfile)
   *outfile=temp;
 }
 
-void base64_decode( const char*infile, unsigned int in_size, char **outfile )
+L4_CV void base64_decode( const char*infile, unsigned int in_size, char **outfile )
 {
   unsigned char in[4], out[3], v;
   int i, len;
index 0d8c31f7c7426e65084342628bfd619434ede7fb..e4fab1b41c6dedd04958fffb311bdc7c263231ec 100644 (file)
@@ -13,7 +13,7 @@
 #include <string.h>
 
 
-int
+L4_CV int
 l4util_kip_kernel_is_ux(l4_kernel_info_t *k)
 {
   const char *s = l4_kip_version_string(k);
@@ -23,7 +23,7 @@ l4util_kip_kernel_is_ux(l4_kernel_info_t *k)
   return 0;
 }
 
-int
+L4_CV int
 l4util_kip_kernel_has_feature(l4_kernel_info_t *k, const char *str)
 {
   const char *s = l4_kip_version_string(k);
@@ -40,7 +40,7 @@ l4util_kip_kernel_has_feature(l4_kernel_info_t *k, const char *str)
   return 0;
 }
 
-unsigned long
+L4_CV unsigned long
 l4util_kip_kernel_abi_version(l4_kernel_info_t *k)
 {
   const char *s = l4_kip_version_string(k);
index 16d4a7e7706c445457264da5bc27c5d6a0a56da5..837644aef4a5fd0aaa615a88927e58989d550b5d 100644 (file)
@@ -25,7 +25,7 @@
  */
 static char buffer[500];
 
-int l4_kprintf(const char *fmt, ...)
+L4_CV int l4_kprintf(const char *fmt, ...)
 {
   va_list list;
   int err;
index 3ccf4b8b0cc23c68599cc4d933605b5fb4ec5aef..db67c82c85c256dc7a856502814fd8896412ad2f 100644 (file)
@@ -110,7 +110,7 @@ __merge(l4la_free_t **first)
   __sanity_check_list(first, __FUNCTION__, "exit");
 }
 
-void 
+L4_CV void
 l4la_free(l4la_free_t **first, void *block, l4_size_t size)
 {
   l4la_free_t **c = first;
@@ -132,7 +132,7 @@ l4la_free(l4la_free_t **first, void *block, l4_size_t size)
   assert(*c != block);
   *c = (l4la_free_t*)block;
   assert(*c != next);
+
   (*c)->next = next;
   (*c)->size = size;
 
@@ -143,7 +143,7 @@ l4la_free(l4la_free_t **first, void *block, l4_size_t size)
   __sanity_check_list(first, __FUNCTION__, "exit");
 }
 
-void *
+L4_CV void *
 l4la_alloc(l4la_free_t **first, l4_size_t size, unsigned align)
 {
   void *ret = 0;
@@ -219,7 +219,7 @@ done:
   return ret;
 }
 
-l4_size_t
+L4_CV l4_size_t
 l4la_avail(l4la_free_t **first)
 {
   __sanity_check_list(first, __FUNCTION__, "entry");
@@ -235,7 +235,7 @@ l4la_avail(l4la_free_t **first)
   return a;
 }
 
-void 
+L4_CV void
 l4la_dump(l4la_free_t **first)
 {
   printf("List_alloc [first=%p]\n", *first);
@@ -249,7 +249,7 @@ l4la_dump(l4la_free_t **first)
     printf("  BUG: loop detected\n");
 }
 
-void 
+L4_CV void
 l4la_init(l4la_free_t **first)
 {
   *first = 0;
index 25eb1ab46c31236461bc93cdd6da716c2737ba04..f6e9b4294a2443f18aff0b44666f8a09a2ab96a4 100644 (file)
@@ -24,7 +24,7 @@
 #include <l4/util/util.h>
 #include <l4/util/bitops.h>
 
-l4_timeout_s
+L4_CV l4_timeout_s
 l4util_micros2l4to(unsigned int mus)
 {
   l4_timeout_s t;
index e5000c8ac12ef4bbce4c72ec99faec38e9a96a59..886b9bc4fff53021445027d9290fa1f750e4bdcf 100644 (file)
@@ -42,7 +42,7 @@ struct parse_cmdline_struct{
 
 #define TRASH(type, val) { type dummy __attribute__ ((unused)) = (val); }
 
-int parse_cmdline(int *argc, const char***argv, char arg0, ...){
+L4_CV int parse_cmdline(int *argc, const char***argv, char arg0, ...){
     va_list va;
     int err;
 
@@ -53,7 +53,7 @@ int parse_cmdline(int *argc, const char***argv, char arg0, ...){
     return err;
 }
 
-int parse_cmdlinev(int *argc, const char***argv, char arg0, va_list va0){
+L4_CV int parse_cmdlinev(int *argc, const char***argv, char arg0, va_list va0){
     va_list va;
     int c, count, shortform, cur_longopt;
     const char*longform, *comment;
@@ -314,7 +314,7 @@ int parse_cmdlinev(int *argc, const char***argv, char arg0, va_list va0){
   return err;
 }
 
-int parse_cmdline_extra(const char*argv0, const char*line, char delim,
+L4_CV int parse_cmdline_extra(const char*argv0, const char*line, char delim,
                        char arg0,...){
     int i, argc_=1;
     char*s, *line_=0;
index f434d85c164414977e4f713a8164fa9145987644..6b726246e6353940e7a83583889016bb91fd25e7 100644 (file)
 
 static unsigned int l4_rand_next = 1;
 
-l4_uint32_t
+L4_CV l4_uint32_t
 l4util_rand(void)
 {
   l4_rand_next = l4_rand_next * 1103515245 + 12345;
   return ((l4_rand_next >>16) & L4_RAND_MAX);
 }
 
-void
+L4_CV void
 l4util_srand (l4_uint32_t seed)
 {
   l4_rand_next = seed;
index d6da61dfdf15ce378a877e94132da508c92bc768..90f291bc589c5407707682b38af45d34973beef1 100644 (file)
@@ -9,7 +9,7 @@
 #include <l4/sys/kdebug.h>
 #include <l4/util/reboot.h>
 
-void
+L4_CV void
 l4util_reboot(void)
 {
   enter_kdebug("*#^");          /* Always available */
index 692b82c9ac9b30b5bf216521b7ec70872552b8ed..0a5be855c47a65598413915076d7dad586d9c834 100644 (file)
@@ -24,7 +24,7 @@
 #include <l4/sys/kernel_object.h>
 #include <l4/util/util.h>
 
-void l4_sleep(int ms)
+L4_CV void l4_sleep(int ms)
 {
   l4_timeout_t to;
   l4_msgtag_t tag;
@@ -43,7 +43,7 @@ void l4_sleep(int ms)
 }
 
 
-void l4_usleep(int us)
+L4_CV void l4_usleep(int us)
 {
   l4_msgtag_t tag;
   l4_timeout_t to;
index 05bbd49b5e4dc3c935ae239a8e846a030a566926..155584fec0bd2585edf34f6ecdc8509693aed1c0 100644 (file)
@@ -13,7 +13,7 @@
  * function implementations
  */
 
-slmap_t*
+L4_CV slmap_t*
 map_new_entry(void* key, unsigned key_size, void* data)
 {
   slmap_t* map;
@@ -33,7 +33,7 @@ map_new_entry(void* key, unsigned key_size, void* data)
   return map;
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_new_sentry(char *key, void* data)
 {
   if (!key)
@@ -41,7 +41,7 @@ map_new_sentry(char *key, void* data)
   return map_new_entry((void*)key, strlen(key), data);
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_append(slmap_t* list, slmap_t* new_entry)
 {
   slmap_t *ret = list;
@@ -53,7 +53,7 @@ map_append(slmap_t* list, slmap_t* new_entry)
   return ret;
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_remove(slmap_t* list, slmap_t* entry)
 {
   slmap_t* ret = list;
@@ -78,7 +78,7 @@ map_remove(slmap_t* list, slmap_t* entry)
  return ret;
 }
 
-void
+L4_CV void
 map_free_entry(slmap_t **entry)
 {
   if (*entry)
@@ -88,7 +88,7 @@ map_free_entry(slmap_t **entry)
     }
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_get_at(slmap_t* list, int n)
 {
   int i=0;
@@ -102,7 +102,7 @@ map_get_at(slmap_t* list, int n)
   return list;
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_add(slmap_t* list, slmap_t* entry)
 {
   if (!entry)
@@ -112,7 +112,7 @@ map_add(slmap_t* list, slmap_t* entry)
   return entry;
 }
 
-void
+L4_CV void
 map_insert_after(slmap_t* after, slmap_t* new_entry)
 {
   if (!new_entry)
@@ -123,7 +123,7 @@ map_insert_after(slmap_t* after, slmap_t* new_entry)
   after->next = new_entry;
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_find(slmap_t* list, void* key, unsigned key_size)
 {
   while (list)
@@ -135,11 +135,10 @@ map_find(slmap_t* list, void* key, unsigned key_size)
   return (slmap_t*)0;
 }
 
-slmap_t*
+L4_CV slmap_t*
 map_sfind(slmap_t* list, const char* key)
 {
   if (!key)
     return (slmap_t*)0;
   return map_find(list, (void*)key, strlen(key));
 }
-
index be07c180d355b242b0754fff7f43fdc78b05faed..b003f7c1200cd990a5468111148dd7ddb9d11b4b 100644 (file)
@@ -51,8 +51,8 @@ struct Sig_handling
                 struct itimerval *__restrict __old) throw();
 
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
-  int handle_exception(L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
+  int handle_exception(L4::Ipc::Iostream &ios);
 };
 
 }
@@ -147,7 +147,7 @@ static bool setup_sig_frame(l4_exc_regs_t *u, int signum)
   return true;
 }
 
-int Sig_handling::handle_exception(L4::Ipc_iostream &ios)
+int Sig_handling::handle_exception(L4::Ipc::Iostream &ios)
 {
   l4_exc_regs_t _u;
   l4_exc_regs_t *u = &_u;
@@ -238,7 +238,7 @@ int Sig_handling::handle_exception(L4::Ipc_iostream &ios)
   return -L4_EOK;
 }
 
-int Sig_handling::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+int Sig_handling::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
@@ -278,7 +278,7 @@ struct Loop_hooks :
          _sig_handling.current_itimerval.it_value.tv_usec));
   }
 
-  void error(l4_msgtag_t res, L4::Ipc_istream &s)
+  void error(l4_msgtag_t res, L4::Ipc::Istream &s)
   {
     long ipc_error = l4_ipc_error(res, s.utcb());
 
index 0fdacb2100b7e8f70af80283480745e5b2e8a899..3b3a8aec4d1fa20b79059e90777b36038c8dc9a3 100644 (file)
@@ -123,7 +123,7 @@ gfxbitmap_font_text(void *fb, l4re_video_view_info_t *vi,
  * \param scale_x Horizonal scale factor.
  * \param scale_y Vertical scale factor.
  */
-void
+L4_CV void
 gfxbitmap_font_text_scale(void *fb, l4re_video_view_info_t *vi,
                           gfxbitmap_font_t font, const char *text, unsigned len,
                           unsigned x, unsigned y,
index 091d2091973cc02ba628da736383965db93c51ae..89b67f2db2c7b1291729b7bd1903e8df62f8f3c6 100644 (file)
@@ -69,14 +69,14 @@ static inline struct psf_font *font_cast(gfxbitmap_font_t font)
 static unsigned char font_yres(struct psf_font *f)
 { return f->header.height; }
 
-unsigned
+L4_CV unsigned
 gfxbitmap_font_width(gfxbitmap_font_t font)
 {
   (void)font;
   return FONT_XRES;
 }
 
-unsigned
+L4_CV unsigned
 gfxbitmap_font_height(gfxbitmap_font_t font)
 {
   struct psf_font *f = font_cast(font);
@@ -90,7 +90,7 @@ get_font_char(struct psf_font *f, unsigned c)
   return &f->data[(FONT_XRES / 8) * font_yres(f) * c];
 }
 
-void *
+L4_CV void *
 gfxbitmap_font_data(gfxbitmap_font_t font, unsigned c)
 {
   struct psf_font *f = font_cast(font);
@@ -100,7 +100,7 @@ gfxbitmap_font_data(gfxbitmap_font_t font, unsigned c)
   return get_font_char(f, c);
 }
 
-void
+L4_CV void
 gfxbitmap_font_text(void *fb, l4re_video_view_info_t *vi,
                     gfxbitmap_font_t font, const char *text, unsigned len,
                     unsigned x, unsigned y,
@@ -139,7 +139,7 @@ gfxbitmap_font_text(void *fb, l4re_video_view_info_t *vi,
 }
 
 
-void
+L4_CV void
 gfxbitmap_font_text_scale(void *fb, l4re_video_view_info_t *vi,
                           gfxbitmap_font_t font, const char *text, unsigned len,
                           unsigned x, unsigned y,
@@ -196,7 +196,7 @@ gfxbitmap_font_text_scale(void *fb, l4re_video_view_info_t *vi,
 }
 
 
-gfxbitmap_font_t
+L4_CV gfxbitmap_font_t
 gfxbitmap_font_get(const char *name)
 {
   unsigned i = 0;
@@ -207,7 +207,7 @@ gfxbitmap_font_get(const char *name)
 }
 
 /** Init lib */
-int
+L4_CV int
 gfxbitmap_font_init(void)
 {
   unsigned chars;
index 3d48a0477e187237620dc71beb45c24520470ff0..68db30b19a416ce8c24ecf08257a7be0d991fa1e 100644 (file)
@@ -65,9 +65,9 @@ public:
   Factory_svr(Factory_interface *factory, Cap_allocator_interface *capif)
     : _factory(factory), _capif(capif) {}
 
-  int factory_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
+  int factory_dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
 
-  virtual L4::Cap<L4::Thread> received_thread(L4::Snd_fpage const &fp) = 0;
+  virtual L4::Cap<L4::Thread> received_thread(L4::Ipc::Snd_fpage const &fp) = 0;
 
   template< typename CT >
   L4::Cap<CT> cap_alloc()
index 89a941e80ce663cae4db8b5a49546bfb6ee6d3b0..025860f6a0ff35135839f3db00475da3647f4889 100644 (file)
@@ -46,8 +46,8 @@ class Scheduler_svr
 public:
   Scheduler_svr(Scheduler_interface *sched)
     : _sched(sched) {}
-  int scheduler_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
-  virtual L4::Cap<L4::Thread> received_thread(L4::Snd_fpage const &fp) = 0;
+  int scheduler_dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
+  virtual L4::Cap<L4::Thread> received_thread(L4::Ipc::Snd_fpage const &fp) = 0;
   virtual ~Scheduler_svr() {}
 
 private:
index 7646f5232fcb4e5f9055e2984c909ab26ff29eb4..7600018792db5f80e294dc9eef7bd37334c13e76 100644 (file)
@@ -30,7 +30,7 @@ class Factory_hndl
 {
 public:
   static int handle_factory(Factory_svr *svr, Factory_interface *fi,
-                            L4::Ipc_iostream &ios)
+                            L4::Ipc::Iostream &ios)
     {
       unsigned long limit;
       L4::Cap<L4::Factory> f = svr->cap_alloc<L4::Factory>();
@@ -44,7 +44,7 @@ public:
     }
 
   static int handle_task(Factory_svr *svr, Factory_interface *fi,
-                         L4::Ipc_iostream &ios)
+                         L4::Ipc::Iostream &ios)
     {
       l4_fpage_t utcb_area;
       L4::Cap<L4::Task> t = svr->cap_alloc<L4::Task>();
@@ -58,7 +58,7 @@ public:
     }
 
   static int handle_thread(Factory_svr *svr, Factory_interface *fi,
-                           L4::Ipc_iostream &ios)
+                           L4::Ipc::Iostream &ios)
     {
       L4::Cap<L4::Thread> t = svr->cap_alloc<L4::Thread>();
       if (!t.is_valid())
@@ -70,10 +70,10 @@ public:
     }
 
   static int handle_gate(Factory_svr *svr, Factory_interface *fi,
-                         L4::Ipc_iostream &ios)
+                         L4::Ipc::Iostream &ios)
     {
       l4_umword_t label;
-      L4::Snd_fpage f;
+      L4::Ipc::Snd_fpage f;
       L4::Cap<L4::Kobject> g = svr->cap_alloc<L4::Kobject>();
       if (!g.is_valid())
         return -L4_ENOMEM;
@@ -88,7 +88,7 @@ public:
     }
 
   static int handle_semaphore(Factory_svr *svr, Factory_interface *fi,
-                              L4::Ipc_iostream &ios)
+                              L4::Ipc::Iostream &ios)
     {
       L4::Cap<L4::K_semaphore> s = svr->cap_alloc<L4::K_semaphore>();
       if (!s.is_valid())
@@ -100,7 +100,7 @@ public:
     }
 
   static int handle_irq(Factory_svr *svr, Factory_interface *fi,
-                        L4::Ipc_iostream &ios)
+                        L4::Ipc::Iostream &ios)
     {
       L4::Cap<L4::Irq> i = svr->cap_alloc<L4::Irq>();
       if (!i.is_valid())
@@ -112,7 +112,7 @@ public:
     }
 };
 
-int Factory_svr::factory_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+int Factory_svr::factory_dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
index ae96a7554f591bc8c72e536e8e77584e82a57a31..c196455d25b75b6f12a4b739dc9f0b2a84464499 100644 (file)
@@ -29,7 +29,7 @@
 
 namespace L4kproxy {
 
-int Scheduler_svr::scheduler_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+int Scheduler_svr::scheduler_dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
@@ -59,7 +59,7 @@ int Scheduler_svr::scheduler_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
     case L4_SCHEDULER_RUN_THREAD_OP:
         {
          l4_sched_param_t sp;
-          L4::Snd_fpage thread;
+          L4::Ipc::Snd_fpage thread;
            {
              l4_umword_t gran_off, prio, quantum;
              ios >> gran_off >> sp.affinity.map >> prio >> quantum >> thread;
index 29c19205c3b39ae212d659ac7baedf0794ee28bb..6e11859cb89b5852149da10cfbaad79eb718dc59 100644 (file)
@@ -160,18 +160,13 @@ public:
     this->map_initial_caps(ntask, Caps::First_free << L4_CAP_SHIFT);
 
     L4::Thread::Attr th_attr;
-
     th_attr.pager(env->rm());
     th_attr.exc_handler(env->rm());
     th_attr.bind((l4_utcb_t*)this->_info.utcbs_start, ntask);
-
     chksys(nthread->control(th_attr));
-    l4_sched_param_t sp;
-    sp.prio = Prios::Default_thread_prio;
-    sp.quantum = 0;
-    sp.affinity = l4_sched_cpu_set(0, ~0);
 
-    chksys(this->run_thread(nthread, sp));
+    chksys(this->run_thread(nthread,
+                            l4_sched_param(Prios::Default_thread_prio)));
 
     nthread->ex_regs(this->_info.entry, this->_stack.target_ptr(), 0);
   }
index 875e1cecf2971b04a58efa7f71b6b44562e2e3ba..667bace3b3de02e99a9266858ae3c0deaa823cfc 100644 (file)
@@ -1,4 +1,4 @@
 
 The dist/ directory contains the unmodified contents of
-libpng-1.5.1.tar.gz.
+libpng-1.5.2.tar.gz.
 
index 00a1f4e2fafe57f54fee34a67fa6e51bebf30af7..177c959287a8d76f5ee22dee1ecec8ab48592377 100644 (file)
@@ -60,7 +60,7 @@
 #define PACKAGE_NAME "libpng"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libpng 1.5.1"
+#define PACKAGE_STRING "libpng 1.5.4"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "libpng"
@@ -69,7 +69,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.5.1"
+#define PACKAGE_VERSION "1.5.4"
 
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
@@ -78,7 +78,7 @@
 /* #undef TM_IN_SYS_TIME */
 
 /* Version number of package */
-#define VERSION "1.5.1"
+#define VERSION "1.5.4"
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
index 5f0c8525bea233036d6396be6ae8084e58d36326..827d17e544c8d68952319b62e7ff05937bcbdb46 100644 (file)
@@ -3,7 +3,7 @@
 
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.5.0 - last changed on February 11, 2011 */
+/* libpng version 1.5.4 - last changed on June 22, 2011 */
 
 /* Copyright (c) 1998-2011 Glenn Randers-Pehrson */
 
@@ -17,7 +17,7 @@
 /* pnglibconf.dfa with respect to the dependencies between the following */
 /* symbols.  It is much better to generate a new file using */
 /* scripts/libpngconf.mak */
-  
+
 #ifndef PNGLCONF_H
 #define PNGLCONF_H
 /* settings */
 #define PNG_ALIGN_MEMORY_SUPPORTED
 #define PNG_BENIGN_ERRORS_SUPPORTED
 #define PNG_bKGD_SUPPORTED
+#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
 #define PNG_CHECK_cHRM_SUPPORTED
 #define PNG_cHRM_SUPPORTED
 #define PNG_CONSOLE_IO_SUPPORTED
 #define PNG_CONVERT_tIME_SUPPORTED
 #define PNG_EASY_ACCESS_SUPPORTED
+/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
 #define PNG_ERROR_TEXT_SUPPORTED
 #define PNG_FIXED_POINT_SUPPORTED
 #define PNG_FLOATING_ARITHMETIC_SUPPORTED
 #define PNG_POINTER_INDEXING_SUPPORTED
 #define PNG_PROGRESSIVE_READ_SUPPORTED
 #define PNG_READ_16BIT_SUPPORTED
-#define PNG_READ_16_TO_8_SUPPORTED
+#define PNG_READ_ALPHA_MODE_SUPPORTED
 #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
 #define PNG_READ_BACKGROUND_SUPPORTED
 #define PNG_READ_BGR_SUPPORTED
 #define PNG_READ_bKGD_SUPPORTED
 #define PNG_READ_cHRM_SUPPORTED
 #define PNG_READ_COMPOSITE_NODIV_SUPPORTED
+#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
 #define PNG_READ_EXPAND_16_SUPPORTED
 #define PNG_READ_EXPAND_SUPPORTED
 #define PNG_READ_FILLER_SUPPORTED
 #define PNG_READ_QUANTIZE_SUPPORTED
 #define PNG_READ_RGB_TO_GRAY_SUPPORTED
 #define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_SCALE_16_TO_8_SUPPORTED
 #define PNG_READ_sCAL_SUPPORTED
 #define PNG_READ_SHIFT_SUPPORTED
 #define PNG_READ_sPLT_SUPPORTED
 #define PNG_READ_sRGB_SUPPORTED
+#define PNG_READ_STRIP_16_TO_8_SUPPORTED
 #define PNG_READ_STRIP_ALPHA_SUPPORTED
 #define PNG_READ_SUPPORTED
 #define PNG_READ_SWAP_ALPHA_SUPPORTED
 #define PNG_WRITE_BGR_SUPPORTED
 #define PNG_WRITE_bKGD_SUPPORTED
 #define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
 #define PNG_WRITE_FILLER_SUPPORTED
 #define PNG_WRITE_FILTER_SUPPORTED
 #define PNG_WRITE_FLUSH_SUPPORTED
 #define PNG_WRITE_INVERT_SUPPORTED
 #define PNG_WRITE_iTXt_SUPPORTED
 #define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
 #define PNG_WRITE_PACK_SUPPORTED
 #define PNG_WRITE_PACKSWAP_SUPPORTED
 #define PNG_WRITE_pCAL_SUPPORTED
 #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
 #define PNG_WRITE_zTXt_SUPPORTED
 #define PNG_zTXt_SUPPORTED
-/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
-/*#undef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED*/
 /* end of options */
 #endif /* PNGLCONF_H */
index 0659ae39d243b698280ca748d97cbcdb04590333..2a9fb6561180a2ca79f6e136b1b900b8f50b171a 100644 (file)
@@ -1,5 +1,5 @@
 
-Libpng 1.5.2 - March 31, 2011
+Libpng 1.5.4 - July 7, 2011
 
 This is a public release of libpng, intended for use in production codes.
 
@@ -8,51 +8,184 @@ Files available for download:
 Source files with LF line endings (for Unix/Linux) and with a
 "configure" script
 
-   libpng-1.5.2.tar.xz (LZMA-compressed, recommended)
-   libpng-1.5.2.tar.gz
-   libpng-1.5.2.tar.bz2
+   libpng-1.5.4.tar.xz (LZMA-compressed, recommended)
+   libpng-1.5.4.tar.gz
+   libpng-1.5.4.tar.bz2
 
 Source files with CRLF line endings (for Windows), without the
 "configure" script
 
-   lpng152.7z  (LZMA-compressed, recommended)
-   lpng152.zip
+   lpng154.7z  (LZMA-compressed, recommended)
+   lpng154.zip
 
 Other information:
 
-   libpng-1.5.2-README.txt
-   libpng-1.5.2-LICENSE.txt
+   libpng-1.5.4-README.txt
+   libpng-1.5.4-LICENSE.txt
 
 Changes since the last public release (1.5.2):
 
-  More -Wshadow fixes for older gcc compilers.  Older gcc versions apparently
-    check formal parameters names in function declarations (as well as
-    definitions) to see if they match a name in the global namespace.
-  Revised PNG_EXPORTA macro to not use an empty parameter, to accommodate the
-    old VisualC++ preprocessor.
-  Turned on interlace handling in png_read_png().
-  Fixed gcc pendantic warnings.
-  Handle longjmp in Cygwin.
-  Fixed png_get_current_row_number() in the interlaced case.
-  Cleaned up ALPHA flags and transformations.
-  Implemented expansion to 16 bits.
-  Fixed mistake in the descriptions of user read_transform and write_transform
-    function prototypes in the manual.  The row_info struct is png_row_infop.
-  Corrected png_get_current_row_number documentation
-  Fixed the read/write row callback documentation.
-    This documents the current behavior, where the callback is called after
-    every row with information pertaining to the next row.
-  Fixed scripts/makefile.vcwin32
-  Updated contrib/pngsuite/README to add the word "modify".
-  Define PNG_ALLOCATED and other attributes to blank when _MSC_VER<1300.
-  ifdef out mask arrays in pngread.c when interlacing is not supported.
-  Added a hint to try CPP=/bin/cpp if "cpp -E" fails in scripts/pnglibconf.mak
-    and in contrib/pngminim/*/makefile, eg., on SunOS 5.10, and removed "strip"
-    from the makefiles.
-  Fixed a bug (present since libpng-1.0.7) that makes png_handle_sPLT() fail
-    to compile when PNG_NO_POINTER_INDEXING is defined (Chubanov Kirill)
-  Don't include standard header files in png.h while building the symbol table,
-    to avoid cpp failure on SunOS (introduced PNG_BUILDING_SYMBOL_TABLE macro).
+  Re-initialize the zlib compressor before compressing non-IDAT chunks.
+  Added API functions to set parameters for zlib compression of non-IDAT
+    chunks.
+  Updated scripts/symbols.def with new API functions.
+  Only compile the new zlib re-initializing code when text or iCCP is
+    supported, using PNG_WRITE_COMPRESSED_TEXT_SUPPORTED macro.
+  Improved the optimization of the zlib CMF byte (see libpng-1.2.6).
+  Optimize the zlib CMF byte in non-IDAT compressed chunks
+  Fixed gcc -ansi -pedantic compile. A strict ANSI system does not have
+    snprintf, and the "__STRICT_ANSI__" detects that condition more reliably
+    than __STDC__ (John Bowler).
+  Removed the PNG_PTR_NORETURN attribute because it too dangerous. It tells
+    the compiler that a user supplied callback (the error handler) does not
+    return, yet there is no guarantee in practice that the application code
+    will correctly implement the error handler because the compiler only
+    issues a warning if there is a mistake (John Bowler).
+  Removed the no-longer-used PNG_DEPSTRUCT macro.
+  Updated the zlib version to 1.2.5 in the VStudio project.
+  Fixed 64-bit builds where png_uint_32 is smaller than png_size_t in
+    pngwutil.c (John Bowler).
+  Fixed bug with stripping the filler or alpha channel when writing, that
+    was introduced in libpng-1.5.2 (bug report by Andrew Church).
+  Updated pngtest.png with the new zlib CMF optimization.
+  Cleaned up conditional compilation code and of background/gamma handling
+    Internal changes only except a new option to avoid compiling the
+    png_build_grayscale_palette API (which is not used at all internally.)
+    The main change is to move the transform tests (READ_TRANSFORMS,
+    WRITE_TRANSFORMS) up one level to the caller of the APIs.  This avoids
+    calls to spurious functions if all transforms are disabled and slightly
+    simplifies those functions.  Pngvalid modified to handle this.
+    A minor change is to stop the strip_16 and expand_16 interfaces from
+    disabling each other; this allows the future alpha premultiplication
+    code to use 16-bit intermediate values while still producing 8-bit output.
+    png_do_background and png_do_gamma have been simplified to take a single
+    pointer to the png_struct rather than pointers to every item required
+    from the png_struct. This makes no practical difference to the internal
+    code.
+  A serious bug in the pngvalid internal routine 'standard_display_init' has
+    been fixed - this failed to initialize the red channel and accidentally
+    initialized the alpha channel twice.
+  Changed png_struct jmp_buf member name from png_jmpbuf to tmp_jmpbuf to
+    avoid a clash with the png_jmpbuf macro on some platforms.
+  Added appropriate feature test macros to ensure libpng sees the correct API
+   _POSIX_SOURCE is defined in pngpriv.h, pngtest.c and pngvalid.c to ensure
+    that POSIX conformant systems disable non-POSIX APIs.  _ISOC99_SOURCE is
+    defined in pngpriv.h to obtain the ISO C99 snprintf definition, when
+    available.
+  Removed png_snprintf and added formatted warning messages.  This change adds
+    internal APIs to allow png_warning messages to have parameters without
+    requiring the host OS to implement snprintf.  As a side effect the
+    dependency of the tIME-supporting RFC1132 code on stdio is removed and
+    PNG_NO_WARNINGS does actually work now.
+  Added PNG_WRITE_OPTIMIZE_CMF_SUPPORTED macro to make the zlib "CMF" byte
+    optimization configureable.
+  Internal functions were added to claim/release the z_stream and, hopefully,
+    make the code more robust.  Also deflateEnd checking is added - previously
+    libpng would ignore an error at the end of the stream.
+  Removed the -D_ALL_SOURCE from definitions for AIX in CMakeLists.txt
+  Implemented premultiplied alpha support: png_set_alpha_mode API
+  Added expand_16 support to the high level interface.
+  Added named value and 'flag' gamma support to png_set_gamma.  Made a minor
+    change from the previous (unreleased) ABI/API to hide the exact value used
+    for Macs - it's not a good idea to embed this in the ABI!
+  Moved macro definitions for PNG_HAVE_IHDR, PNG_HAVE_PLTE, and PNG_AFTER_IDAT
+    from pngpriv.h to png.h because they must be visible to applications
+    that call png_set_unknown_chunks().
+  Check for up->location !PNG_AFTER_IDAT when writing unknown chunks
+    before IDAT.
+  Improved "pngvalid --speed" to exclude more of pngvalid from the time.
+  Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt
+  The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative
+    parameters are supplied by the caller), while in the absence of cHRM
+    sRGB/Rec 709 values are still used.
+  The bKGD chunk no longer overwrites the background value set by
+    png_set_background(), allowing the latter to be used before the file
+    header is read. It never performed any useful function to override
+    the default anyway.
+  Added memory overwrite and palette image checks to pngvalid.c
+    Previously palette image code was poorly checked. Since the transformation
+    code has a special palette path in most cases this was a severe weakness.
+  Minor cleanup and some extra checking in pngrutil.c and pngrtran.c. When
+    expanding an indexed image, always expand to RGBA if transparency is
+    present.
+  Reversed earlier 1.5.3 change of transformation order; move png_expand_16
+    back where it was.  The change doesn't work because it requires 16-bit
+    gamma tables when the code only generates 8-bit ones.  This fails
+    silently; the libpng code just doesn't do any gamma correction.  Moving
+    the tests back leaves the old, inaccurate, 8-bit gamma calculations, but
+    these are clearly better than none!
+  png_set_background() and png_expand_16() did not work together correctly.
+    This problem is present in 1.5.2; if png_set_background is called with
+    need_expand false and the matching 16 bit color libpng erroneously just
+    treats it as an 8-bit color because of where png_do_expand_16 is in the
+    transform list.  This simple fix reduces the supplied colour to 8-bits,
+    so it gets smashed, but this is better than the current behavior.
+  Added tests for expand16, more fixes for palette image tests to pngvalid.
+    Corrects the code for palette image tests and disables attempts to
+    validate palette colors.
+  Fixed uninitialized memory read in png_format_buffer() (Bug report by
+    Frank Busse, related to CVE-2004-0421).
+  Fixed png_handle_sCAL which is broken in 1.5; added sCAL to pngtest.png
+  Revised documentation about png_set_user_limits() to say that it also affects
+    png writing.
+  Revised handling of png_set_user_limits() so that it can increase the
+    limit beyond the PNG_USER_WIDTH|HEIGHT_MAX; previously it could only
+    reduce it.
+  Make the 16-to-8 scaling accurate. Dividing by 256 with no rounding is
+    wrong (high by one) 25% of the time. Dividing by 257 with rounding is
+    wrong in 128 out of 65536 cases. Getting the right answer all the time
+    without division is easy.
+  Added "_SUPPORTED" to the PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION macro.
+  Added projects/owatcom, an IDE project for OpenWatcom to replace
+    scripts/makefile.watcom.  This project works with OpenWatcom 1.9. The
+    IDE autogenerates appropriate makefiles (libpng.mk) for batch processing.
+    The project is configurable, unlike the Visual Studio project, so long
+    as the developer has an awk.
+  Changed png_set_gAMA to limit the gamma value range so that the inverse
+    of the stored value cannot overflow the fixed point representation,
+    and changed other things OpenWatcom warns about.
+  Revised pngvalid.c to test PNG_ALPHA_MODE_SUPPORTED correctly. This allows
+    pngvalid to build when ALPHA_MODE is not supported, which is required if
+    it is to build on libpng 1.4.
+  Removed string/memory macros that are no longer used and are not
+    necessarily fully supportable, particularly png_strncpy and png_snprintf.
+  Added log option to pngvalid.c and attempted to improve gamma messages.
+  People found the presence of a beta release following an rc release
+    to be confusing; therefore we bump the version to libpng-1.5.4beta01
+    and there will be no libpng-1.5.3 release.
+  Moved definitions of PNG_HAVE_IHDR, PNG_AFTER_IDAT, and PNG_HAVE_PLTE
+    outside of an unknown-chunk block in png.h because they are also
+    needed for other uses.
+  Added png_set_scale_16() API, to match inaccurate results from previous
+    libpng versions, configurable with PNG_READ_SCALE_16_TO_8_SUPPORTED.
+  Fixed a problem in png_do_expand_palette() exposed by optimization in
+    1.5.3beta06
+  Also removed a spurious and confusing "trans" member ("trans") from png_info.
+  The palette expand optimization prevented expansion to an intermediate RGBA
+    form if tRNS was present but alpha was marked to be stripped; this exposed
+    a check for tRNS in png_do_expand_palette() which is inconsistent with the
+    code elsewhere in libpng.
+  Added PNG_TRANSFORM_SCALE_16 to the high-level read transforms.
+  If PNG_READ_16_TO_8_ACCURATE_SCALE is not enabled, png_set_scale_16()
+    and png_do_scale_16_to_8() aren't built.
+  Revised contrib/visupng, gregbook, and pngminim to demonstrate scale_16_to_8
+  Fixed pngvalid, simplified macros, added checking for 0 in sCAL.
+    The ACCURATE scale macro is no longer defined in libpng-1.5 - call the
+    png_scale_16_to_8 API.  Made sure that PNG_READ_16_TO_8 is still defined
+    if the png_strip_16_to_8 API is present.  png_check_fp_number now
+    maintains some state so that positive, negative and zero values are
+    identified.  sCAL uses these to be strictly spec conformant.
+  Define PNG_ALLOCATED to "restrict" only if MSC_VER >= 1400.
+
+Send comments/corrections/commendations to png-mng-implement at lists.sf.net
+(subscription required; visit
+https://lists.sourceforge.net/lists/listinfo/png-mng-implement
+to subscribe)
+or to glennrp at users.sourceforge.net
+
+Glenn R-P
+*/ }
+#endif
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
index fb069121a45024e4904e7f4ea0636f183b7ec350..628d7f04533fac5c9e683a487d1f7cba3aeac2e1 100644 (file)
@@ -15,7 +15,7 @@ Version 0.3
   fixed some bugs in writer
   interfaced with zlib 0.5
   added K&R support
-  added check for 64 KB blocks for 16 bit machines
+  added check for 64 KB blocks for 16-bit machines
 
 Version 0.4
   cleaned up code and commented code
@@ -74,7 +74,7 @@ Version 0.82 [September, 1995]
 Version 0.85 [December, 1995]
   added more medium model code (almost everything's a far)
   added i/o, error, and memory callback functions
-  fixed some bugs (16 bit, 4 bit interlaced, etc.)
+  fixed some bugs (16-bit, 4-bit interlaced, etc.)
   added first run progressive reader (barely tested)
 
 Version 0.86 [January, 1996]
@@ -2935,7 +2935,7 @@ Version 1.5.0beta36 [July 29, 2010]
     PNG_INTERLACE transform and to get the number of rows in the current
     pass.
   A new test program, pngvalid.c, validates the gamma code.
-  Errors in the 16 bit gamma correction (overflows) have been corrected.
+  Errors in the 16-bit gamma correction (overflows) have been corrected.
   cHRM chunk testing is done consistently (previously the floating point
     API bypassed it, because the test really didn't work on FP, now the test
     is performed on the actual values to be stored in the PNG file so it
@@ -3208,9 +3208,9 @@ Version 1.5.1beta09 [January 24, 2011]
     pngvalid contains tests of transforms, which tests are currently disabled
     because they are incompletely tested.  gray_to_rgb was failing to expand
     the bit depth for smaller bit depth images; this seems to be a long
-    standing error and resulted, apparently, in invalid output.  The
-    documentation did not accurately describe what libpng really does when
-    converting RGB to gray.
+    standing error and resulted, apparently, in invalid output
+    (CVE-2011-0408, CERT VU#643140).  The documentation did not accurately
+    describe what libpng really does when converting RGB to gray.
 
 Version 1.5.1beta10 [January 27, 2010]
   Fixed incorrect examples of callback prototypes in the manual, that were
@@ -3227,7 +3227,7 @@ Version 1.5.1beta10 [January 27, 2010]
 Version 1.5.1beta11 [January 28, 2011]
   Changed PNG_UNUSED from "param=param;" to "{if(param){}}".
   Corrected local variable type in new API png_process_data_skip()
-    The type was self-evidently incorrect but only causes problems on 64 bit
+    The type was self-evidently incorrect but only causes problems on 64-bit
     architectures.
   Added transform tests to pngvalid and simplified the arguments.
 
@@ -3285,6 +3285,228 @@ Version 1.5.2rc03 [March 24, 2011]
     to avoid cpp failure on SunOS (introduced PNG_BUILDING_SYMBOL_TABLE macro).
 
 Version 1.5.2 [March 31, 2011]
+  No changes.
+
+Version 1.5.3beta01 [April 1, 2011]
+  Re-initialize the zlib compressor before compressing non-IDAT chunks.
+  Added API functions to set parameters for zlib compression of non-IDAT
+    chunks.
+
+Version 1.5.3beta02 [April 3, 2011]
+  Updated scripts/symbols.def with new API functions.
+  Only compile the new zlib re-initializing code when text or iCCP is
+    supported, using PNG_WRITE_COMPRESSED_TEXT_SUPPORTED macro.
+  Improved the optimization of the zlib CMF byte (see libpng-1.2.6beta03).
+  Optimize the zlib CMF byte in non-IDAT compressed chunks
+
+Version 1.5.3beta03 [April 16, 2011]
+  Fixed gcc -ansi -pedantic compile. A strict ANSI system does not have
+    snprintf, and the "__STRICT_ANSI__" detects that condition more reliably
+    than __STDC__ (John Bowler).
+  Removed the PNG_PTR_NORETURN attribute because it too dangerous. It tells
+    the compiler that a user supplied callback (the error handler) does not
+    return, yet there is no guarantee in practice that the application code
+    will correctly implement the error handler because the compiler only
+    issues a warning if there is a mistake (John Bowler).
+  Removed the no-longer-used PNG_DEPSTRUCT macro.
+  Updated the zlib version to 1.2.5 in the VStudio project.
+  Fixed 64-bit builds where png_uint_32 is smaller than png_size_t in
+    pngwutil.c (John Bowler).
+  Fixed bug with stripping the filler or alpha channel when writing, that
+    was introduced in libpng-1.5.2beta01 (bug report by Andrew Church).
+
+Version 1.5.3beta04 [April 27, 2011]
+  Updated pngtest.png with the new zlib CMF optimization.
+  Cleaned up conditional compilation code and of background/gamma handling
+    Internal changes only except a new option to avoid compiling the
+    png_build_grayscale_palette API (which is not used at all internally.)
+    The main change is to move the transform tests (READ_TRANSFORMS,
+    WRITE_TRANSFORMS) up one level to the caller of the APIs.  This avoids
+    calls to spurious functions if all transforms are disabled and slightly
+    simplifies those functions.  Pngvalid modified to handle this.
+    A minor change is to stop the strip_16 and expand_16 interfaces from
+    disabling each other; this allows the future alpha premultiplication
+    code to use 16-bit intermediate values while still producing 8-bit output.
+    png_do_background and png_do_gamma have been simplified to take a single
+    pointer to the png_struct rather than pointers to every item required
+    from the png_struct. This makes no practical difference to the internal
+    code.
+  A serious bug in the pngvalid internal routine 'standard_display_init' has
+    been fixed - this failed to initialize the red channel and accidentally
+    initialized the alpha channel twice.
+  Changed png_struct jmp_buf member name from png_jmpbuf to tmp_jmpbuf to
+    avoid a possible clash with the png_jmpbuf macro on some platforms.
+
+Version 1.5.3beta05 [May 6, 2011]
+  Added the "_POSIX_SOURCE" feature test macro to ensure libpng sees the
+    correct API. _POSIX_SOURCE is defined in pngpriv.h, pngtest.c and
+    pngvalid.c to ensure that POSIX conformant systems disable non-POSIX APIs.
+  Removed png_snprintf and added formatted warning messages.  This change adds
+    internal APIs to allow png_warning messages to have parameters without
+    requiring the host OS to implement snprintf.  As a side effect the
+    dependency of the tIME-supporting RFC1132 code on stdio is removed and
+    PNG_NO_WARNINGS does actually work now.
+  Pass "" instead of '\0' to png_default_error() in png_err().  This mistake
+    was introduced in libpng-1.2.20beta01.
+  Added PNG_WRITE_OPTIMIZE_CMF_SUPPORTED macro to make the zlib "CMF" byte
+    optimization configureable.
+  IDAT compression failed if preceded by a compressed text chunk (bug
+    introduced in libpng-1.5.3beta01-02).  This was because the attempt to
+    reset the zlib stream in png_write_IDAT happened after the first IDAT
+    chunk had been deflated - much too late.  In this change internal
+    functions were added to claim/release the z_stream and, hopefully, make
+    the code more robust.  Also deflateEnd checking is added - previously
+    libpng would ignore an error at the end of the stream.
+
+Version 1.5.3beta06 [May 8, 2011]
+  Removed the -D_ALL_SOURCE from definitions for AIX in CMakeLists.txt
+  Implemented premultiplied alpha support: png_set_alpha_mode API
+
+Version 1.5.3beta07 [May 11, 2011]
+  Added expand_16 support to the high level interface.
+  Added named value and 'flag' gamma support to png_set_gamma.  Made a minor
+    change from the previous (unreleased) ABI/API to hide the exact value used
+    for Macs - it's not a good idea to embed this in the ABI!
+  Moved macro definitions for PNG_HAVE_IHDR, PNG_HAVE_PLTE, and PNG_AFTER_IDAT
+    from pngpriv.h to png.h because they must be visible to applications
+    that call png_set_unknown_chunks().
+  Check for up->location !PNG_AFTER_IDAT when writing unknown chunks
+    before IDAT.
+
+Version 1.5.3beta08 [May 16, 2011]
+  Improved "pngvalid --speed" to exclude more of pngvalid from the time.
+  Documented png_set_alpha_mode(), other changes in libpng.3/libpng-manual.txt
+  The cHRM chunk now sets the defaults for png_set_rgb_to_gray() (when negative
+    parameters are supplied by the caller), while in the absence of cHRM
+    sRGB/Rec 709 values are still used.
+  The bKGD chunk no longer overwrites the background value set by
+    png_set_background(), allowing the latter to be used before the file
+    header is read. It never performed any useful function to override
+    the default anyway.
+  Added memory overwrite and palette image checks to pngvalid.c
+    Previously palette image code was poorly checked. Since the transformation
+    code has a special palette path in most cases this was a severe weakness.
+  Minor cleanup and some extra checking in pngrutil.c and pngrtran.c. When
+    expanding an indexed image, always expand to RGBA if transparency is
+    present.
+
+Version 1.5.3beta09 [May 17, 2011]
+  Reversed earlier 1.5.3 change of transformation order; move png_expand_16
+    back where it was.  The change doesn't work because it requires 16-bit
+    gamma tables when the code only generates 8-bit ones.  This fails
+    silently; the libpng code just doesn't do any gamma correction.  Moving
+    the tests back leaves the old, inaccurate, 8-bit gamma calculations, but
+    these are clearly better than none!
+
+Version 1.5.3beta10 [May 20, 2011]
+
+  png_set_background() and png_expand_16() did not work together correctly.
+    This problem is present in 1.5.2; if png_set_background is called with
+    need_expand false and the matching 16 bit color libpng erroneously just
+    treats it as an 8-bit color because of where png_do_expand_16 is in the
+    transform list.  This simple fix reduces the supplied colour to 8-bits,
+    so it gets smashed, but this is better than the current behavior.
+  Added tests for expand16, more fixes for palette image tests to pngvalid.
+    Corrects the code for palette image tests and disables attempts to
+    validate palette colors.
+
+Version 1.5.3rc01 [June 3, 2011]
+  No changes.
+
+Version 1.5.3rc02 [June 8, 2011]
+  Fixed uninitialized memory read in png_format_buffer() (Bug report by
+    Frank Busse, CVE-2011-2501, related to CVE-2004-0421).
+
+Version 1.5.3beta11 [June 11, 2011]
+  Fixed png_handle_sCAL which is broken in 1.5; added sCAL to pngtest.png
+  Revised documentation about png_set_user_limits() to say that it also affects
+    png writing.
+  Revised handling of png_set_user_limits() so that it can increase the
+    limit beyond the PNG_USER_WIDTH|HEIGHT_MAX; previously it could only
+    reduce it.
+  Make the 16-to-8 scaling accurate. Dividing by 256 with no rounding is
+    wrong (high by one) 25% of the time. Dividing by 257 with rounding is
+    wrong in 128 out of 65536 cases. Getting the right answer all the time
+    without division is easy.
+  Added "_SUPPORTED" to the PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION macro.
+  Added projects/owatcom, an IDE project for OpenWatcom to replace
+    scripts/makefile.watcom.  This project works with OpenWatcom 1.9. The
+    IDE autogenerates appropriate makefiles (libpng.mk) for batch processing.
+    The project is configurable, unlike the Visual Studio project, so long
+    as the developer has an awk.
+  Changed png_set_gAMA to limit the gamma value range so that the inverse
+    of the stored value cannot overflow the fixed point representation,
+    and changed other things OpenWatcom warns about.
+  Revised pngvalid.c to test PNG_ALPHA_MODE_SUPPORTED correctly. This allows
+    pngvalid to build when ALPHA_MODE is not supported, which is required if
+    it is to build on libpng 1.4.
+  Removed string/memory macros that are no longer used and are not
+    necessarily fully supportable, particularly png_strncpy and png_snprintf.
+  Added log option to pngvalid.c and attempted to improve gamma messages.
+  
+Version 1.5.3 [omitted]
+  People found the presence of a beta release following an rc release
+    to be confusing; therefore we bump the version to libpng-1.5.4beta01
+    and there will be no libpng-1.5.3 release.
+
+Version 1.5.4beta01 [June 14, 2011]
+  Made it possible to undefine PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+    to get the same (inaccurate) output as libpng-1.5.2 and earlier.
+  Moved definitions of PNG_HAVE_IHDR, PNG_AFTER_IDAT, and PNG_HAVE_PLTE
+    outside of an unknown-chunk block in png.h because they are also
+    needed for other uses.
+
+Version 1.5.4beta02 [June 14, 2011]
+  Fixed and clarified LEGACY 16-to-8 scaling code.
+  Added png_set_chop_16() API, to match inaccurate results from previous
+    libpng versions.
+  Removed the ACCURATE and LEGACY options (they are no longer useable)
+  Use the old scaling method for background if png_set_chop_16() was
+    called.
+  Made png_set_chop_16() API removeable by disabling PNG_CHOP_16_TO_8_SUPPORTED
+
+Version 1.5.4beta03 [June 15, 2011]
+  Fixed a problem in png_do_expand_palette() exposed by optimization in
+    1.5.3beta06
+  Also removed a spurious and confusing "trans" member ("trans") from png_info.
+  The palette expand optimization prevented expansion to an intermediate RGBA
+    form if tRNS was present but alpha was marked to be stripped; this exposed
+    a check for tRNS in png_do_expand_palette() which is inconsistent with the
+    code elsewhere in libpng.
+  Correction to the expand_16 code; removed extra instance of
+    png_set_scale_16_to_8 from pngpriv.h
+
+Version 1.5.4beta04 [June 16, 2011]
+  Added a missing "#ifdef PNG_READ_BACKGROUND_SUPPORTED/#endif" in pngrtran.c
+  Added PNG_TRANSFORM_CHOP_16 to the high-level read transforms.
+  Made PNG_READ_16_TO_8_ACCURATE_SCALE configurable again.  If this is
+    not enabled, png_set_strip_16() and png_do_scale_16_to_8() aren't built.
+  Revised contrib/visupng, gregbook, and pngminim to demonstrate chop_16_to_8
+
+Version 1.5.4beta05 [June 16, 2011]
+  Renamed png_set_strip_16() to png_set_scale_16() and renamed
+    png_set_chop_16() to png_set_strip(16) in an attempt to minimize the
+    behavior changes between libpng14 and libpng15.
+
+Version 1.5.4beta06 [June 18, 2011]
+  Fixed new bug that was causing both strip_16 and scale_16 to be applied.
+
+Version 1.5.4beta07 [June 19, 2011]
+  Fixed pngvalid, simplified macros, added checking for 0 in sCAL.
+    The ACCURATE scale macro is no longer defined in 1.5 - call the
+    png_scale_16_to_8 API.  Made sure that PNG_READ_16_TO_8 is still defined
+    if the png_strip_16_to_8 API is present.  png_check_fp_number now
+    maintains some state so that positive, negative and zero values are
+    identified.  sCAL uses these to be strictly spec conformant.
+
+Version 1.5.4beta08 [June 23, 2011]
+  Fixed pngvalid if ACCURATE_SCALE is defined.
+  Updated scripts/pnglibconf.h.prebuilt.
+
+Version 1.5.4rc01 [June 30, 2011]
+  Define PNG_ALLOCATED to "restrict" only if MSC_VER >= 1400.
+
+Version 1.5.4 [July 7, 2011]
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
index 8f2b7e8b45257009b6ac7d61b5564f9209afd0ac..cc158508d1143ae0393121c48d4e7086f0312736 100644 (file)
@@ -33,7 +33,7 @@ enable_testing()
 
 set(PNGLIB_MAJOR 1)
 set(PNGLIB_MINOR 5)
-set(PNGLIB_RELEASE 2)
+set(PNGLIB_RELEASE 4)
 set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR})
 set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE})
 
@@ -147,10 +147,6 @@ set(pngtest_sources
 
 add_definitions(-DPNG_CONFIGURE_LIBPNG)
 
-if(_AIX)
-  add_definitions(-D_ALL_SOURCE)
-endif(_AIX)
-
 if(MSVC)
   add_definitions(-DPNG_NO_MODULEDEF -D_CRT_SECURE_NO_DEPRECATE)
 endif(MSVC)
@@ -264,7 +260,7 @@ install(CODE ${PNG_CONFIG_INSTALL_CODE})
 # SET UP LINKS
 if(PNG_SHARED)
   set_target_properties(${PNG_LIB_NAME} PROPERTIES
-#   VERSION 15.${PNGLIB_RELEASE}.1.5.2
+#   VERSION 15.${PNGLIB_RELEASE}.1.5.4
     VERSION 15.${PNGLIB_RELEASE}.0
     SOVERSION 15
     CLEAN_DIRECT_OUTPUT 1)
index 6e4808cc0bc2df01d16b6c43c544814e5fb31fd5..89f5243f164fadc978039326f92b5b4965def541 100644 (file)
@@ -10,7 +10,7 @@ this sentence.
 
 This code is released under the libpng license.
 
-libpng versions 1.2.6, August 15, 2004, through 1.5.2, March 31, 2011, are
+libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
 Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
 distributed according to the same disclaimer and license as libpng-1.2.5
 with the following individual added to the list of Contributing Authors
@@ -108,4 +108,4 @@ certification mark of the Open Source Initiative.
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-March 31, 2011
+July 7, 2011
index 7b8c494c38d653cdc82e072d3ce0562bff0a7477..af2f58bacddc36bc7319c3e1fb0551ec00ea6c94 100644 (file)
@@ -18,13 +18,13 @@ pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 pngvalid_SOURCES = pngvalid.c
 pngvalid_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 TESTS = test-pngtest.sh test-pngvalid-simple.sh test-pngvalid-full.sh
-TESTS_ENVIRONMENT= srcdir=$(srcdir) 
+TESTS_ENVIRONMENT= srcdir=$(srcdir)
 
 # man pages
 dist_man_MANS= libpng.3 libpngpf.3 png.5
 
 # generate the -config scripts if required
-binconfigs= libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@-config 
+binconfigs= libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@-config
 EXTRA_SCRIPTS= libpng-config libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@-config
 bin_SCRIPTS= @binconfigs@
 
@@ -159,10 +159,10 @@ scripts/symbols.chk: scripts/checksym.awk scripts/symbols.def scripts/symbols.ou
 # be empty - no non-standard defines
 scripts/pnglibconf.dfn: scripts/pnglibconf.dfa scripts/options.awk
        rm -f $@ dfn?.out
-       test -z "$(CPPFLAGS)" 
+       test -z "$(CPPFLAGS)"
        echo "com @PNGLIB_VERSION@ STANDARD API DEFINITION" |\
        $(AWK) -f ${srcdir}/scripts/options.awk out=dfn1.out\
-           logunsupported=2 - ${srcdir}/scripts/pnglibconf.dfa 1>&2
+           logunsupported=4 - ${srcdir}/scripts/pnglibconf.dfa 1>&2
        $(AWK) -f ${srcdir}/scripts/options.awk out=dfn2.out dfn1.out 1>&2
        rm dfn1.out
        mv dfn2.out $@
index 5410f1bfbc79791c3a7fbcbf2d19634873126704..20e0111c4e442964138fe0817547d8a8e4a0c34e 100644 (file)
@@ -252,7 +252,7 @@ am__tar = @am__tar@
 am__untar = @am__untar@
 
 # generate the -config scripts if required
-binconfigs = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@-config 
+binconfigs = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@-config
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -310,7 +310,7 @@ pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 pngvalid_SOURCES = pngvalid.c
 pngvalid_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 TESTS = test-pngtest.sh test-pngvalid-simple.sh test-pngvalid-full.sh
-TESTS_ENVIRONMENT = srcdir=$(srcdir) 
+TESTS_ENVIRONMENT = srcdir=$(srcdir)
 
 # man pages
 dist_man_MANS = libpng.3 libpngpf.3 png.5
@@ -413,7 +413,7 @@ config.h: stamp-h1
 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
        @rm -f stamp-h1
        cd $(top_builddir) && $(SHELL) ./config.status config.h
-$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
        ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
        rm -f stamp-h1
        touch $@
@@ -455,7 +455,7 @@ clean-libLTLIBRARIES:
          echo "rm -f \"$${dir}/so_locations\""; \
          rm -f "$${dir}/so_locations"; \
        done
-libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la: $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_OBJECTS) $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_DEPENDENCIES) 
+libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la: $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_OBJECTS) $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_DEPENDENCIES)
        $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LINK) -rpath $(libdir) $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_OBJECTS) $(libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_LIBADD) $(LIBS)
 
 clean-checkPROGRAMS:
@@ -466,10 +466,10 @@ clean-checkPROGRAMS:
        list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
        echo " rm -f" $$list; \
        rm -f $$list
-pngtest$(EXEEXT): $(pngtest_OBJECTS) $(pngtest_DEPENDENCIES) 
+pngtest$(EXEEXT): $(pngtest_OBJECTS) $(pngtest_DEPENDENCIES)
        @rm -f pngtest$(EXEEXT)
        $(LINK) $(pngtest_OBJECTS) $(pngtest_LDADD) $(LIBS)
-pngvalid$(EXEEXT): $(pngvalid_OBJECTS) $(pngvalid_DEPENDENCIES) 
+pngvalid$(EXEEXT): $(pngvalid_OBJECTS) $(pngvalid_DEPENDENCIES)
        @rm -f pngvalid$(EXEEXT)
        $(LINK) $(pngvalid_OBJECTS) $(pngvalid_LDADD) $(LIBS)
 install-binSCRIPTS: $(bin_SCRIPTS)
@@ -1319,7 +1319,7 @@ scripts/symbols.chk: scripts/checksym.awk scripts/symbols.def scripts/symbols.ou
 # be empty - no non-standard defines
 scripts/pnglibconf.dfn: scripts/pnglibconf.dfa scripts/options.awk
        rm -f $@ dfn?.out
-       test -z "$(CPPFLAGS)" 
+       test -z "$(CPPFLAGS)"
        echo "com @PNGLIB_VERSION@ STANDARD API DEFINITION" |\
        $(AWK) -f ${srcdir}/scripts/options.awk out=dfn1.out\
            logunsupported=1 - ${srcdir}/scripts/pnglibconf.dfa 1>&2
index 6a7cb33b212a4c7745aae7fbb06b8d7d355cbf31..71396a8d9d0faa07a95084aca0642d3fbd9de80a 100644 (file)
@@ -1,4 +1,4 @@
-README for libpng version 1.5.2 - March 31, 2011 (shared library 15.0)
+README for libpng version 1.5.4 - July 7, 2011 (shared library 15.0)
 See the note about version numbers near the top of png.h
 
 See INSTALL for instructions on how to install libpng.
@@ -114,19 +114,16 @@ given in previous versions of this document.  He and Andreas will
 read mail addressed to the png-implement list, however.
 
 Please do not send general questions about PNG.  Send them to
-the (png-list at ccrc.wustl.edu, subscription required, write to
-majordomo at ccrc.wustl.edu with "subscribe png-list" in your message).
-On the other hand,
-please do not send libpng questions to that address, send them to me
-or to the png-implement list.  I'll
-get them in the end anyway.  If you have a question about something
+png-mng-misc at lists.sf.net (subscription required; visit
+https://lists.sourceforge.net/lists/listinfo/png-mng-misc to
+subscribe).  If you have a question about something
 in the PNG specification that is related to using libpng, send it
 to me.  Send me any questions that start with "I was using libpng,
 and ...".  If in doubt, send questions to me.  I'll bounce them
 to others, if necessary.
 
 Please do not send suggestions on how to change PNG.  We have
-been discussing PNG for nine years now, and it is official and
+been discussing PNG for sixteen years now, and it is official and
 finished.  If you have suggestions for libpng, however, I'll
 gladly listen.  Even if your suggestion is not used immediately,
 it may be used later.
index 2d1a687b7ab54208ae58ae5298dd1777fecda9e5..54c5192f251e0aafc1e597131146bf1b51a9a1b8 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for libpng 1.5.2.
+# Generated by GNU Autoconf 2.68 for libpng 1.5.4.
 #
 # Report bugs to <png-mng-implement@lists.sourceforge.net>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='libpng'
 PACKAGE_TARNAME='libpng'
-PACKAGE_VERSION='1.5.2'
-PACKAGE_STRING='libpng 1.5.2'
+PACKAGE_VERSION='1.5.4'
+PACKAGE_STRING='libpng 1.5.4'
 PACKAGE_BUGREPORT='png-mng-implement@lists.sourceforge.net'
 PACKAGE_URL=''
 
@@ -1307,7 +1307,7 @@ if test "$ac_init_help" = "long"; then
   # 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 <<_ACEOF
-\`configure' configures libpng 1.5.2 to adapt to many kinds of systems.
+\`configure' configures libpng 1.5.4 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1377,7 +1377,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libpng 1.5.2:";;
+     short | recursive ) echo "Configuration of libpng 1.5.4:";;
    esac
   cat <<\_ACEOF
 
@@ -1485,7 +1485,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libpng configure 1.5.2
+libpng configure 1.5.4
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1908,7 +1908,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libpng $as_me 1.5.2, which was
+It was created by libpng $as_me 1.5.4, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -2723,7 +2723,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='libpng'
- VERSION='1.5.2'
+ VERSION='1.5.4'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2787,10 +2787,10 @@ fi
 
 
 
-PNGLIB_VERSION=1.5.2
+PNGLIB_VERSION=1.5.4
 PNGLIB_MAJOR=1
 PNGLIB_MINOR=5
-PNGLIB_RELEASE=2
+PNGLIB_RELEASE=4
 
 
 
@@ -13040,7 +13040,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libpng $as_me 1.5.2, which was
+This file was extended by libpng $as_me 1.5.4, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -13106,7 +13106,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libpng config.status 1.5.2
+libpng config.status 1.5.4
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
index 05540c6cd1fe55b744f54d892cd20b2d16c5d50c..f2800f62c47641c1a216cd05746e24f0d52925f2 100644 (file)
@@ -18,15 +18,15 @@ AC_PREREQ(2.59)
 
 dnl Version number stuff here:
 
-AC_INIT([libpng], [1.5.2], [png-mng-implement@lists.sourceforge.net])
+AC_INIT([libpng], [1.5.4], [png-mng-implement@lists.sourceforge.net])
 AM_INIT_AUTOMAKE
 dnl stop configure from automagically running automake
 AM_MAINTAINER_MODE
 
-PNGLIB_VERSION=1.5.2
+PNGLIB_VERSION=1.5.4
 PNGLIB_MAJOR=1
 PNGLIB_MINOR=5
-PNGLIB_RELEASE=2
+PNGLIB_RELEASE=4
 
 dnl End of version number stuff
 
index 782c555b7a6ff0202c0150b63410991920addae4..c0d27f48735f8aae5b8eaed03849f52fc3d10115 100644 (file)
@@ -2,7 +2,7 @@
 #if 0 /* in case someone actually tries to compile this */
 
 /* example.c - an example of using libpng
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * This file has been placed in the public domain by the authors.
  * Maintained 1998-2011 Glenn Randers-Pehrson
  * Maintained 1996, 1997 Andreas Dilger)
  * see also the programs in the contrib directory.
  */
 
+#define _POSIX_SOURCE 1  /* libpng and zlib are POSIX-compliant.  You may
+                          * change this if your application uses non-POSIX
+                          * extensions. */
+
 #include "png.h"
 
  /* The png_jmpbuf() macro, used in error handling, became available in
@@ -183,8 +187,15 @@ void read_png(FILE *fp, unsigned int sig_read)  /* File is already open */
     * are mutually exclusive.
     */
 
-   /* Tell libpng to strip 16 bit/color files down to 8 bits/color */
+   /* Tell libpng to strip 16 bit/color files down to 8 bits/color.
+    * Use accurate scaling if it's available, otherwise just chop off the
+    * low byte.
+    */
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+    png_set_scale_16(png_ptr);
+#else
    png_set_strip_16(png_ptr);
+#endif
 
    /* Strip alpha bytes from the input data without combining with the
     * background (not recommended).
index 4693408460124f9c1ad64368c6c6ba72e6537419..c91b99cf60d5fcb0f3b95eec5096eec922c35a44 100644 (file)
@@ -1,6 +1,6 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.5.2 - March 31, 2011
+ libpng version 1.5.4 - July 7, 2011
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2011 Glenn Randers-Pehrson
@@ -11,7 +11,7 @@ libpng-manual.txt - A description on how to use and modify libpng
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.5.2 - March 31, 2011
+ libpng versions 0.97, January 1998, through 1.5.4 - July 7, 2011
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2011 Glenn Randers-Pehrson
 
@@ -198,9 +198,9 @@ reconfiguration of pnglibconf.h.  To reconfigure pnglibconf.h it must either be
 rebuilt from scripts/pnglibconf.dfa using awk or it must be edited by hand.
 
 Hand editing is achieved by copying scripts/pnglibconf.h.prebuilt and changing
-the lines defining the supported features, paying very close attention to the
-'option' information in scripts/pnglibconf.dfa that describes those features and
-their requirements.  This is easy to get wrong.
+the lines defining the supported features, paying very close attention to
+the 'option' information in scripts/pnglibconf.dfa that describes those
+features and their requirements.  This is easy to get wrong.
 
 B. Configuration using DFA_XTRA
 
@@ -348,21 +348,12 @@ create the structure, so your application should check for that.
        return (ERROR);
     }
 
-    png_infop end_info = png_create_info_struct(png_ptr);
-
-    if (!end_info)
-    {
-       png_destroy_read_struct(&png_ptr, &info_ptr,
-          (png_infopp)NULL);
-       return (ERROR);
-    }
-
 If you want to use your own memory allocation routines,
 use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use
 png_create_read_struct_2() instead of png_create_read_struct():
 
     png_structp png_ptr = png_create_read_struct_2
-       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+        (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
         user_error_fn, user_warning_fn, (png_voidp)
         user_mem_ptr, user_malloc_fn, user_free_fn);
 
@@ -374,7 +365,7 @@ handling and memory alloc/free functions.
 When libpng encounters an error, it expects to longjmp back
 to your routine.  Therefore, you will need to call setjmp and pass
 your png_jmpbuf(png_ptr).  If you read the file from different
-routines, you will need to update the jmpbuf field every time you enter
+routines, you will need to update the longjmp buffer every time you enter
 a new routine that will call a png_*() function.
 
 See your documentation of setjmp/longjmp for your compiler for more
@@ -392,6 +383,9 @@ free any memory.
        return (ERROR);
     }
 
+Pass (png_infopp)NULL instead of &end_info if you didn't create
+an end_info structure.
+
 If you would rather avoid the complexity of setjmp/longjmp issues,
 you can compile libpng with PNG_NO_SETJMP, in which case
 errors will result in a call to PNG_ABORT() which defaults to abort().
@@ -603,7 +597,7 @@ large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns.
 Since very few applications really need to process such large images,
 we have imposed an arbitrary 1-million limit on rows and columns.
 Larger images will be rejected immediately with a png_error() call. If
-you wish to override this limit, you can use
+you wish to change this limit, you can use
 
    png_set_user_limits(png_ptr, width_max, height_max);
 
@@ -613,6 +607,10 @@ anyway because of potential buffer overflow conditions).
 
 You should put this statement after you create the PNG structure and
 before calling png_read_info(), png_read_png(), or png_process_data().
+
+When writing a PNG datastream, put this statement before calling
+png_write_info() or png_write_png().
+
 If you need to retrieve the limits that are being applied, use
 
    width_max = png_get_user_width_max(png_ptr);
@@ -643,6 +641,234 @@ and you can retrieve the limit with
 Any chunks that would cause either of these limits to be exceeded will
 be ignored.
 
+Information about your system
+
+If you intend to display the PNG or to incorporate it in other image data you
+need to tell libpng information about your display or drawing surface so that
+libpng can convert the values in the image to match the display.
+
+From libpng-1.5.4 this information can be set before reading the PNG file
+header.  In earlier versions png_set_gamma() existed but behaved incorrectly if
+called before the PNG file header had been read and png_set_alpha_mode() did not
+exist.
+
+If you need to support versions prior to libpng-1.5.4 test the version number
+and follow the procedures described in the appropriate manual page.
+
+You give libpng the encoding expected by your system expressed as a 'gamma'
+value.  You can also specify a default encoding for the PNG file in
+case the required information is missing from the file.  By default libpng
+assumes that the PNG data matches your system, to keep this default call:
+
+   png_set_gamma(png_ptr, screen_gamma, 1/screen_gamma/*file gamma*/);
+
+or you can use the fixed point equivalent:
+
+   png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, PNG_FP_1/screen_gamma);
+
+If you don't know the gamma for you system it is probably 2.2 - a good
+approximation to the IEC standard for display systems (sRGB).  If images are
+too contrasty or washed out you got the value wrong - check your system
+documentation!
+
+Many systems permit the system gamma to be changed via a lookup table in the
+display driver, a few systems, including older Macs, change the response by
+default.  As of 1.5.4 three special values are available to handle common
+situations:
+
+   PNG_DEFAULT_sRGB: Indicates that the system conforms to the IEC 61966-2-1
+                     standard.  This matches almost all systems.
+   PNG_GAMMA_MAC_18: Indicates that the system is an older (pre Mac OS 10.6)
+                     Apple Macintosh system with the default settings.
+   PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates that the
+                     system expects data with no gamma encoding.
+
+You would use the linear (unencoded) value if you need to process the pixel
+values further because this avoids the need to decode and reencode each
+component value whenever arithmetic is performed.  A lot of graphics software
+uses linear values for this reason, often with higher precision component values
+to preserve overall accuracy.
+
+The second thing you may need to tell libpng about is how your system handles
+alpha channel information.  Some, but not all, PNG files contain an alpha
+channel.  To display these files correctly you need to compose the data onto a
+suitable background, as described in the PNG specification.
+
+Libpng only supports composing onto a single color (using png_set_background;
+see below.)  Otherwise you must do the composition yourself and, in this case,
+you may need to call png_set_alpha_mode:
+
+   png_set_alpha_mode(png_ptr, mode, screen_gamma);
+
+The screen_gamma value is the same as the argument to png_set_gamma, however how
+it affects the output depends on the mode.  png_set_alpha_mode() sets the file
+gamma default to 1/screen_gamma, so normally you don't need to call
+png_set_gamma.  If you need different defaults call png_set_gamma() before
+png_set_alpha_mode() - if you call it after it will override the settings made
+by png_set_alpha_mode().
+
+The mode is as follows:
+
+    PNG_ALPHA_PNG: The data is encoded according to the PNG specification.  Red,
+green and blue, or gray, components are gamma encoded color
+values and are not premultiplied by the alpha value.  The
+alpha value is a linear measure of the contribution of the
+pixel to the corresponding final output pixel.
+
+You should normally use this format if you intend to perform
+color correction on the color values; most, maybe all, color
+correction software has no handling for the alpha channel and,
+anyway, the math to handle pre-multiplied component values is
+unnecessarily complex.
+
+Before you do any arithmetic on the component values you need
+to remove the gamma encoding and multiply out the alpha
+channel.  See the PNG specification for more detail.  It is
+important to note that when an image with an alpha channel is
+scaled, linear encoded, pre-multiplied component values must
+be used!
+
+The remaining modes assume you don't need to do any further color correction or
+that if you do your color correction software knows all about alpha (it
+probably doesn't!)
+
+    PNG_ALPHA_STANDARD:  The data libpng produces is encoded in the standard way
+assumed by most correctly written graphics software.
+The gamma encoding will be removed by libpng and the
+linear component values will be pre-multiplied by the
+alpha channel.
+
+With this format the final image must be re-encoded to
+match the display gamma before the image is displayed.
+If your system doesn't do that, yet still seems to
+perform arithmetic on the pixels without decoding them,
+it is broken - check out the modes below.
+
+With PNG_ALPHA_STANDARD libpng always produces linear
+component values, whatever screen_gamma you supply.  The
+screen_gamma value is, however, used as a default for
+the file gamma if the PNG file has no gamma information.
+
+If you call png_set_gamma() after png_set_alpha_mode() you
+will override the linear encoding.  Instead the
+pre-multiplied pixel values will be gamma encoded but
+the alpha channel will still be linear.  This may
+actually match the requirements of some broken software,
+but it is unlikely.
+
+While linear 8-bit data is often used it has
+insufficient precision for any image with a reasonable
+dynamic range.  To avoid problems, and if your software
+supports it, use png_set_expand_16() to force all
+components to 16 bits.
+
+    PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD except that
+completely opaque pixels are gamma encoded according to
+the screen_gamma value.  Pixels with alpha less than 1.0
+will still have linear components.
+
+Use this format if you have control over your
+compositing software and do don't do other arithmetic
+(such as scaling) on the data you get from libpng.  Your
+compositing software can simply copy opaque pixels to
+the output but still has linear values for the
+non-opaque pixels.
+
+In normal compositing, where the alpha channel encodes
+partial pixel coverage (as opposed to broad area
+translucency), the inaccuracies of the 8-bit
+representation of non-opaque pixels are irrelevant.
+
+You can also try this format if your software is broken;
+it might look better.
+
+    PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD however all component values,
+including the alpha channel are gamma encoded.  This is
+an appropriate format to try if your software, or more
+likely hardware, is totally broken: if it performs
+linear arithmetic directly on gamma encoded values.
+
+In most cases of broken software or hardware the bug in the final display
+manifests as a subtle halo around composited parts of the image.  You may not
+even perceive this as a halo; the composited part of the image may simply appear
+separate from the background, as though it had been cut out of paper and pasted
+on afterward.
+
+If you don't have to deal with bugs in software or hardware, or if you can fix
+them, there are three recommended ways of using png_set_alpha_mode():
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG,
+       screen_gamma);
+
+You can do color correction on the result (libpng does not currently
+support color correction internally.)  When you handle the alpha channel
+you need to undo the gamma encoding and multiply out the alpha.
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD,
+       screen_gamma);
+   png_set_expand_16(png_ptr);
+
+If you are using the high level interface don't call png_set_expand_16();
+instead pass PNG_TRANSFORM_EXPAND_16 to the interface.
+
+With this mode you can't do color correction, but you can do arithmetic,
+including composition and scaling, on the data without further processing.
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED,
+       screen_gamma);
+
+You can avoid the expansion to 16-bit components with this mode, but you
+lose the ability to scale the image or perform other linear arithmetic.
+All you can do is compose the result onto a matching output.  Since this
+mode is libpng specific you also need to write your own composition
+software.
+
+If you don't need, or can't handle, the alpha channel you can call
+png_set_background() to remove it by compositing against a fixed color.  Don't
+call png_set_strip_alpha() to do this - it will leave spurious pixel values in
+transparent parts of this image.
+
+   png_set_background(png_ptr, &background_color,
+       PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);
+
+The background_color is an RGB or grayscale value according to the data format
+libpng will produce for you.  Because you don't yet know the format of the PNG
+file if you call png_set_background at this point you must arrange for the
+format produced by libpng to always have 8-bit or 16-bit components and then
+store the color as an 8-bit or 16-bit color as appropriate.  The color contains
+separate gray and RGB component values, so you can let libpng produce gray or
+RGB output according to the input format, but low bit depth grayscale images
+must always be converted to at least 8-bit format.  (Even low low bit depth
+grayscale images can't have an alpha channel they can have a transparent
+color!)
+
+You set the transforms you need later, either as flags to the high level
+interface or libpng API calls for the low level interface.  For reference the
+settings and API calls required are:
+
+8-bit values:
+   PNG_TRANSFORM_SCALE_16 | PNG_EXPAND
+   png_set_expand(png_ptr); png_set_scale_16(png_ptr);
+
+   If you must get exactly the same inaccurate results
+   produced by default in versions prior to libpng-1.5.4,
+   use PNG_TRANSFORM_STRIP_16 and png_set_strip_16(png_ptr)
+   instead.
+
+16-bit values:
+   PNG_TRANSFORM_EXPAND_16
+   png_set_expand_16(png_ptr);
+
+In either case palette image data will be expanded to RGB.  If you just want
+color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr)
+to the list.
+
+Calling png_set_background before the PNG file header is read will not work
+prior to libpng-1.5.4.  Because the failure may result in unexpected warnings or
+errors it is therefore much safer to call png_set_background after the head has
+been read.  Unfortunately this means that prior to libpng-1.5.4 it cannot be
+used with the high level interface.
+
 The high-level read interface
 
 At this point there are two ways to proceed; through the high-level
@@ -652,8 +878,10 @@ the entire image into memory, and (b) the input transformations
 you want to do are limited to the following set:
 
     PNG_TRANSFORM_IDENTITY      No transformation
-    PNG_TRANSFORM_STRIP_16      Strip 16-bit samples to
-                                8 bits
+    PNG_TRANSFORM_SCALE_16      Strip 16-bit samples to
+                                8-bit accurately
+    PNG_TRANSFORM_STRIP_16      Chop 16-bit samples to
+                                8-bit less accurately
     PNG_TRANSFORM_STRIP_ALPHA   Discard the alpha channel
     PNG_TRANSFORM_PACKING       Expand 1, 2 and 4-bit
                                 samples to bytes
@@ -672,6 +900,7 @@ you want to do are limited to the following set:
     PNG_TRANSFORM_SWAP_ENDIAN   Byte-swap 16-bit samples
     PNG_TRANSFORM_GRAY_TO_RGB   Expand grayscale samples
                                 to RGB (or GA to RGBA)
+    PNG_TRANSFORM_EXPAND_16     Expand samples to 16 bits
 
 (This excludes setting a background color, doing gamma transformation,
 quantizing, and setting filler.)  If this is the case, simply do this:
@@ -740,6 +969,22 @@ call to png_read_info().
 
 This will process all chunks up to but not including the image data.
 
+This also copies some of the data from the PNG file into the decode structure
+for use in later transformations.  Important information copied in is:
+
+1) The PNG file gamma from the gAMA chunk.  This overwrites the default value
+provided by an earlier call to png_set_gamma or png_set_alpha_mode.
+
+2) Prior to libpng-1.5.4 the background color from a bKGd chunk.  This
+damages the information provided by an earlier call to png_set_background
+resulting in expected behavior.  Libpng-1.5.4 no longer does this.
+
+3) The number of significant bits in each component value.  Libpng uses this to
+optimize gamma handling by reducing the internal lookup table sizes.
+
+4) The transparent color information from a tRNS chunk.  This can be modified by
+a later call to png_set_tRNS.
+
 Querying the info structure
 
 Functions are used to get the information from the info_ptr once it
@@ -1103,7 +1348,7 @@ forms:
        converted to microns and back without some loss
        of precision.
 
-For more information, see the png_info definition in png.h and the
+For more information, see the
 PNG specification for chunk contents.  Be careful with trusting
 rowbytes, as some of the transformations could increase the space
 needed to hold a row (expand, filler, gray_to_rgb, etc.).
@@ -1138,17 +1383,20 @@ to handle any special transformations of the image data.  The various
 ways to transform the data will be described in the order that they
 should occur.  This is important, as some of these change the color
 type and/or bit depth of the data, and some others only work on
-certain color types and bit depths.  Even though each transformation
-checks to see if it has data that it can do something with, you should
-make sure to only enable a transformation if it will be valid for the
-data.  For example, don't swap red and blue on grayscale data.
+certain color types and bit depths.
 
-The colors used for the background and transparency values should be
-supplied in the same format/depth as the current image data.  They
-are stored in the same format/depth as the image data in a bKGD or tRNS
-chunk, so this is what libpng expects for this data.  The colors are
-transformed to keep in sync with the image data when an application
-calls the png_read_update_info() routine (see below).
+Transformations you request are ignored if they don't have any meaning for a
+particular input data format.  However some transformations can have an effect
+as a result of a previous transformation.  If you specify a contradictory set of
+transformations, for example both adding and removing the alpha channel, you
+cannot predict the final result.
+
+The color used for the transparency values should be supplied in the same
+format/depth as the current image data.  It is stored in the same format/depth
+as the image data in a tRNS chunk, so this is what libpng expects for this data.
+
+The color used for the background value depends on the need_expand argument as
+described below.
 
 Data will be decoded into the supplied row buffers packed into bytes
 unless the library has been told to transform it into another format.
@@ -1158,12 +1406,12 @@ byte, unless png_set_packing() is called.  8-bit RGB data will be stored
 in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha()
 is called to insert filler bytes, either before or after each RGB triplet.
 16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant
-byte of the color value first, unless png_set_strip_16() is called to
+byte of the color value first, unless png_set_scale_16() is called to
 transform it to regular RGB RGB triplets, or png_set_filler() or
 png_set_add alpha() is called to insert filler bytes, either before or
 after each RRGGBB triplet.  Similarly, 8-bit or 16-bit grayscale data can
-be modified with
-png_set_filler(), png_set_add_alpha(), or png_set_strip_16().
+be modified with png_set_filler(), png_set_add_alpha(), png_set_strip_16(),
+or png_set_scale_16().
 
 The following code transforms grayscale images of less than 8 to 8 bits,
 changes paletted images to RGB, and adds a full alpha channel if there is
@@ -1197,27 +1445,25 @@ severe accuracy loss.
       png_set_expand_16(png_ptr);
 
 PNG can have files with 16 bits per channel.  If you only can handle
-8 bits per channel, this will strip the pixels down to 8 bit.
+8 bits per channel, this will strip the pixels down to 8-bit.
 
     if (bit_depth == 16)
-       png_set_strip_16(png_ptr);
+       png_set_scale_16(png_ptr);
 
-If, for some reason, you don't need the alpha channel on an image,
-and you want to remove it rather than combining it with the background
-(but the image author certainly had in mind that you *would* combine
-it with the background, so that's what you should probably do):
+If you need to process the alpha channel on the image separately from the image
+data (for example if you convert it to a bitmap mask) it is possible to have
+libpng strip the channel leaving just RGB or gray data:
 
     if (color_type & PNG_COLOR_MASK_ALPHA)
        png_set_strip_alpha(png_ptr);
 
-See below for png_set_background(), which does the correct composition on a
-single opaque color.  This is probably what you should do in all cases rather
-than use png_set_strip_alpha() - unless you know for sure that it is the wrong
-thing to do.
+If you strip the alpha channel you need to find some other way of dealing with
+the information.  If, instead, you want to convert the image to an opaque
+version with no alpha channel use png_set_background; see below.
 
 As of libpng version 1.5.2, almost all useful expansions are supported, the
-major ommissions are convertion of grayscale to indexed images (which can be
-done trivially in the application) and convertion of indexed to grayscale (which
+major ommissions are conversion of grayscale to indexed images (which can be
+done trivially in the application) and conversion of indexed to grayscale (which
 can be done by a trivial manipulation of the palette.)
 
 In the following table, the 01 means grayscale with depth<8, 31 means
@@ -1254,8 +1500,7 @@ Within the matrix,
          png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() if there
          is no transparency in the original or the final format).
      "C" means the transformation is obtained by png_set_gray_to_rgb().
-     "G" means the transformation is obtained by png_set_rgb_to_gray() or
-         png_set_rgb_to_Y().
+     "G" means the transformation is obtained by png_set_rgb_to_gray().
      "P" means the transformation is obtained by
          png_set_expand_palette_to_rgb().
      "p" means the transformation is obtained by png_set_packing().
@@ -1347,8 +1592,8 @@ with alpha.
 
     if (color_type == PNG_COLOR_TYPE_RGB ||
         color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-       png_set_rgb_to_gray_fixed(png_ptr, error_action,
-           int red_weight, int green_weight);
+       png_set_rgb_to_gray(png_ptr, error_action, double red_weight,
+          double green_weight);
 
     error_action = 1: silently do the conversion
 
@@ -1361,122 +1606,89 @@ with alpha.
                       image has any pixel where
                       red != green or red != blue
 
-    red_weight:       weight of red component times 100000
+    red_weight:       weight of red component
 
-    green_weight:     weight of green component times 100000
+    green_weight:     weight of green component
                       If either weight is negative, default
-                      weights (21268, 71514) are used.
+                      weights are used.
+
+In the corresponding fixed point API the red_weight and green_weight values are
+simply scaled by 100,000:
+
+    png_set_rgb_to_gray(png_ptr, error_action, png_fixed_point red_weight,
+       png_fixed_point green_weight);
 
 If you have set error_action = 1 or 2, you can
 later check whether the image really was gray, after processing
 the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
 It will return a png_byte that is zero if the image was gray or
-1 if there were any non-gray pixels.  bKGD and sBIT data
+1 if there were any non-gray pixels.  Background and sBIT data
 will be silently converted to grayscale, using the green channel
-data, regardless of the error_action setting.
+data for sBIT, regardless of the error_action setting.
 
-With red_weight+green_weight<=100000,
-the normalized graylevel is computed:
+The default values come from the PNG file cHRM chunk if present, otherwise the
+defaults correspond to the ITU-R recommendation 709, and also the sRGB color
+space, as recommended in the Charles Poynton's Colour FAQ,
+<http://www.poynton.com/>, in section 9:
 
-    int rw = red_weight * 65536;
-    int gw = green_weight * 65536;
-    int bw = 65536 - (rw + gw);
-    gray = (rw*red + gw*green + bw*blue)/65536;
-
-The default values approximate those recommended in the Charles
-Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
-Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net>
+   <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9>
 
     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
 
-Libpng approximates this with integers scaled by 32768:
-
-    Y = (6968 * R + 23434 * G + 2366 * B)/32768
-
 The calculation is done in a linear colorspace, if the image gamma
 can be determined.
 
-If you have a grayscale and you are using png_set_expand_gray_1_2_4_to_8(),
-png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to
-a higher bit-depth, you must either supply the background color as a gray
-value at the original file bit-depth (need_expand = 1) or else supply the
-background color as an RGB triplet at the final, expanded bit depth
-(need_expand = 0).  Similarly, if you are reading a paletted image, you
-must either supply the background color as a palette index (need_expand = 1)
-or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+The png_set_background() function has been described already, it tells libpng to
+composite images with alpha or simple transparency against the supplied
+background color.  For compatibility with versions of libpng earlier than
+libpng-1.5.4 it is recommended that you call the function after reading the file
+header, even if you don't want to use the color in a bKGD chunk, if one exists.
+
+If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page).  You
+need to tell libpng how the color is represented, both the format of the
+component values in the color (the number of bits) and the gamme encoding of the
+color.  The function takes two arguments, background_gamma_mode and need_expand
+to convey this information, however only two combinations are like to be useful:
 
     png_color_16 my_background;
     png_color_16p image_background;
 
     if (png_get_bKGD(png_ptr, info_ptr, &image_background))
        png_set_background(png_ptr, image_background,
-           PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+           PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1);
     else
        png_set_background(png_ptr, &my_background,
-           PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+           PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1);
 
-The png_set_background() function tells libpng to composite images
-with alpha or simple transparency against the supplied background
-color.  If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
-you may use this color, or supply another color more suitable for
-the current display (e.g., the background color from a web page).  You
-need to tell libpng whether the color is in the gamma space of the
-display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
-(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
-that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
-know why anyone would use this, but it's here).
-
-To properly display PNG images on any kind of system, the application needs
-to know what the display gamma is.  Ideally, the user will know this, and
-the application will allow them to set it.  One method of allowing the user
-to set the display gamma separately for each system is to check for a
-SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be
-correctly set.
-
-Note that display_gamma is the overall gamma correction required to produce
-pleasing results, which depends on the lighting conditions in the surrounding
-environment.  In a dim or brightly lit room, no compensation other than
-the physical gamma exponent of the monitor is needed, while in a dark room
-a slightly smaller exponent is better.
-
-   double gamma, screen_gamma;
-
-   if (/* We have a user-defined screen
-       gamma value */)
-   {
-      screen_gamma = user_defined_screen_gamma;
-   }
 
-   /* One way that applications can share the same
-      screen gamma value */
-   else if ((gamma_str = getenv("SCREEN_GAMMA"))
-      != NULL)
-   {
-      screen_gamma = (double)atof(gamma_str);
-   }
+The second call was described above - my_background is in the format of the
+final, display, output produced by libpng.  Because you now know the format of
+the PNG it is possible to avoid the need to choose either 8-bit or 16-bit
+output and to retain palette images (the palette colors will be modified
+appropriately and the tRNS chunk removed.)  However, if you are doing this,
+take great care not to ask for transformations without checking first that
+they apply!
 
-   /* If we don't have another value */
-   else
-   {
-      screen_gamma = 2.2; /* A good guess for a
-           PC monitor in a bright office or a dim room */
+In the first call the background color has the original bit depth and color type
+of the PNG file.  So, for palette images the color is supplied as a palette
+index and for low bit greyscale images the color is a reduced bit value in
+image_background->gray.
 
-      screen_gamma = 2.0; /* A good guess for a
-           PC monitor in a dark room */
+If you didn't call png_set_gamma() before reading the file header, for example
+if you need your code to remain compatible with older versions of libpng prior
+to libpng-1.5.4, this is the place to call it.
 
-      screen_gamma = 1.7 or 1.0;  /* A good
-           guess for Mac systems */
-   }
+Do not call it if you called png_set_alpha_mode(); doing so will damage the
+settings put in place by png_set_alpha_mode().  (If png_set_alpha_mode() is
+supported then you can certainly do png_set_gamma() before reading the PNG
+header.)
 
-The functions png_set_gamma() and its fixed point equivalent
-png_set_gamma_fixed() handle gamma transformations of the data.
-Pass both the file gamma and the current screen_gamma.  If the file does
-not have a gamma value, you can pass one anyway if you have an idea what
-it is (usually 0.45455 is a good guess for GIF images on PCs).  Note
-that file gammas are inverted from screen gammas.  See the discussions
-on gamma in the PNG specification for an excellent description of what
-gamma is, and why all applications should support it.  It is strongly
-recommended that PNG viewers support gamma correction.
+This API unconditionally sets the screen and file gamma values, so it will
+override the value in the PNG file unless it is called before the PNG file
+reading starts.  For this reason you must always call it with the PNG file
+value when you call it in this position:
 
    if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
       png_set_gamma(png_ptr, screen_gamma, file_gamma);
@@ -1532,7 +1744,7 @@ This function can also be used to invert grayscale and gray-alpha images:
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
       png_set_invert_mono(png_ptr);
 
-PNG files store 16 bit pixels in network byte order (big-endian,
+PNG files store 16-bit pixels in network byte order (big-endian,
 ie. most significant bits first).  This code changes the storage to the
 other way (little-endian, i.e. least significant bits first, the
 way PCs store them):
@@ -1824,15 +2036,39 @@ low-level interface, you can finish reading the file.  If you are
 interested in comments or time, which may be stored either before or
 after the image data, you should pass the separate png_info struct if
 you want to keep the comments from before and after the image
-separate.  If you are not interested, you can pass NULL.
+separate.
+
+    png_infop end_info = png_create_info_struct(png_ptr);
+
+    if (!end_info)
+    {
+       png_destroy_read_struct(&png_ptr, &info_ptr,
+           (png_infopp)NULL);
+       return (ERROR);
+    }
 
    png_read_end(png_ptr, end_info);
 
+If you are not interested, you should still call png_read_end()
+but you can pass NULL, avoiding the need to create an end_info structure.
+
+   png_read_end(png_ptr, (png_infop)NULL);
+
+If you don't call png_read_end(), then your file pointer will be
+left pointing to the first chunk after the last IDAT, which is probably
+not what you want if you expect to read something beyond the end of
+the PNG datastream.
+
 When you are done, you can free all memory allocated by libpng like this:
 
    png_destroy_read_struct(&png_ptr, &info_ptr,
        &end_info);
 
+or, if you didn't create an end_info structure,
+
+   png_destroy_read_struct(&png_ptr, &info_ptr,
+       (png_infopp)NULL);
+
 It is also possible to individually free the info_ptr members that
 point to libpng-allocated storage with the following function:
 
@@ -2295,11 +2531,11 @@ with zlib) for details on the compression levels.
 
     #include zlib.h
 
-    /* set the zlib compression level */
+    /* Set the zlib compression level */
     png_set_compression_level(png_ptr,
         Z_BEST_COMPRESSION);
 
-    /* set other zlib parameters */
+    /* Set other zlib parameters for compressing IDAT */
     png_set_compression_mem_level(png_ptr, 8);
     png_set_compression_strategy(png_ptr,
         Z_DEFAULT_STRATEGY);
@@ -2307,7 +2543,15 @@ with zlib) for details on the compression levels.
     png_set_compression_method(png_ptr, 8);
     png_set_compression_buffer_size(png_ptr, 8192)
 
-extern PNG_EXPORT(void,png_set_zbuf_size)
+    /* Set zlib parameters for text compression
+     * If you don't call these, the parameters
+     * fall back on those defined for IDAT chunks
+     */
+    png_set_text_compression_mem_level(png_ptr, 8);
+    png_set_text_compression_strategy(png_ptr,
+        Z_DEFAULT_STRATEGY);
+    png_set_text_compression_window_bits(png_ptr, 15);
+    png_set_text_compression_method(png_ptr, 8);
 
 Setting the contents of info for output
 
@@ -2813,7 +3057,7 @@ is required by PNG.
 
     png_set_shift(png_ptr, &sig_bit);
 
-PNG files store 16 bit pixels in network byte order (big-endian,
+PNG files store 16-bit pixels in network byte order (big-endian,
 ie. most significant bits first).  This code would be used if they are
 supplied the other way (little-endian, i.e. least significant bits
 first, the way PCs store them):
@@ -3229,7 +3473,7 @@ the simpler ones to get an idea of how they work.  Try to find a similar
 transformation to the one you want to add and copy off of it.  More details
 can be found in the comments inside the code itself.
 
-Configuring for 16 bit platforms
+Configuring for 16-bit platforms
 
 You will want to look into zconf.h to tell zlib (and thus libpng) that
 it cannot allocate more then 64K at a time.  Even if you can, the memory
@@ -3735,7 +3979,8 @@ The png_zalloc() function no longer zeroes out the memory that it
 allocates.
 
 Support for dithering was disabled by default in libpng-1.4.0, because
-been well tested and doesn't actually "dither".  The code was not
+it has not been well tested and doesn't actually "dither".
+The code was not
 removed, however, and could be enabled by building libpng with
 PNG_READ_DITHER_SUPPORTED defined.  In libpng-1.4.2, this support
 was reenabled, but the function was renamed png_set_quantize() to
@@ -3796,8 +4041,9 @@ absolutely necessary) interlace an image.
 libpng 1.5.0 adds an API png_longjmp(png_ptr, value).  This API calls
 the application-provided png_longjmp_ptr on the internal, but application
 initialized, jmpbuf.  It is provided as a convenience to avoid the need
-to use the png_jmpbuf macro, which had the unnecessary side effect of
-resetting the internal png_longjmp_ptr value.
+initialized, longjmp buffer.  It is provided as a convenience to avoid
+the need to use the png_jmpbuf macro, which had the unnecessary side
+effect of resetting the internal png_longjmp_ptr value.
 
 libpng 1.5.0 includes a complete fixed point API.  By default this is
 present along with the corresponding floating point API.  In general the
@@ -3851,6 +4097,25 @@ PNG_NO_USE_READ_MACROS before including png.h.  Notice that this is
 only supported from 1.5.0 -defining PNG_NO_USE_READ_MACROS prior to 1.5.0
  will lead to a link failure.
 
+Prior to libpng-1.5.4, the zlib compressor used the same set of parameters
+when compressing the IDAT data and textual data such as zTXt and iCCP.
+In libpng-1.5.4 we reinitialized the zlib stream for each type of data.
+We added five png_set_text_*() functions for setting the parameters to
+use with textual data.
+
+Prior to libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+option was off by default, and slightly inaccurate scaling occurred.
+This option can no longer be turned off, and the choice of accurate
+or inaccurate 16-to-8 scaling is by using the new png_set_scale_16_to_8()
+API for accurate scaling or the old png_set_strip_16_to_8() API for simple
+chopping.
+
+Prior to libpng-1.5.4, the png_set_user_limits() function could only be
+used to reduce the width and height limits from the value of
+PNG_USER_WIDTH_MAX and PNG_USER_HEIGHT_MAX, although this document said
+that it could be used to override them.  Now this function will reduce or
+increase the limits.
+
 B. Changes to the build and configuration of libpng
 
 Details of internal changes to the library code can be found in the CHANGES
@@ -4159,13 +4424,13 @@ Other rules can be inferred by inspecting the libpng source.
 
 XIV. Y2K Compliance in libpng
 
-March 31, 2011
+July 7, 2011
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
 
 This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.5.2 are Y2K compliant.  It is my belief that earlier
+upward through 1.5.4 are Y2K compliant.  It is my belief that earlier
 versions were also Y2K compliant.
 
 Libpng only has three year fields.  One is a 2-byte unsigned integer that
index 3a7ca6e666aeedb09ba3ee265240f790bbca1334..04518cae22e3395556860a39b39bbf34e5f16449 100644 (file)
@@ -1,6 +1,6 @@
-.TH LIBPNG 3 "March 31, 2011"
+.TH LIBPNG 3 "July 7, 2011"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
+libpng \- Portable Network Graphics (PNG) Reference Library 1.5.4
 .SH SYNOPSIS
 \fI\fB
 
@@ -512,6 +512,14 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
 
 \fI\fB
 
+\fBvoid png_set_alpha_mode (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImode\fP\fB, double \fIoutput_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_alpha_mode_fixed (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImode\fP\fB, png_fixed_point \fIoutput_gamma\fP\fB);\fP
+
+\fI\fB
+
 \fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP
 
 \fI\fB
@@ -756,6 +764,10 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
 
 \fI\fB
 
+\fBvoid png_set_scale_16 (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
 \fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP
 
 \fI\fB
@@ -800,6 +812,26 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
 
 \fI\fB
 
+\fBvoid png_set_text_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_text_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_text_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_text_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid \fP\fIpng_set_text_compression_method\fP\fB, (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod)\fP\fB);\fP
+
+\fI\fB
+
 \fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP
 
 \fI\fB
@@ -923,7 +955,7 @@ Following is a copy of the libpng-manual.txt file that accompanies libpng.
 .SH LIBPNG.TXT
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.5.2 - March 31, 2011
+ libpng version 1.5.4 - July 7, 2011
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2011 Glenn Randers-Pehrson
@@ -934,7 +966,7 @@ libpng-manual.txt - A description on how to use and modify libpng
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.5.2 - March 31, 2011
+ libpng versions 0.97, January 1998, through 1.5.4 - July 7, 2011
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2011 Glenn Randers-Pehrson
 
@@ -1121,9 +1153,9 @@ reconfiguration of pnglibconf.h.  To reconfigure pnglibconf.h it must either be
 rebuilt from scripts/pnglibconf.dfa using awk or it must be edited by hand.
 
 Hand editing is achieved by copying scripts/pnglibconf.h.prebuilt and changing
-the lines defining the supported features, paying very close attention to the
-'option' information in scripts/pnglibconf.dfa that describes those features and
-their requirements.  This is easy to get wrong.
+the lines defining the supported features, paying very close attention to
+the 'option' information in scripts/pnglibconf.dfa that describes those
+features and their requirements.  This is easy to get wrong.
 
 B. Configuration using DFA_XTRA
 
@@ -1271,21 +1303,12 @@ create the structure, so your application should check for that.
        return (ERROR);
     }
 
-    png_infop end_info = png_create_info_struct(png_ptr);
-
-    if (!end_info)
-    {
-       png_destroy_read_struct(&png_ptr, &info_ptr,
-          (png_infopp)NULL);
-       return (ERROR);
-    }
-
 If you want to use your own memory allocation routines,
 use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use
 png_create_read_struct_2() instead of png_create_read_struct():
 
     png_structp png_ptr = png_create_read_struct_2
-       (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+        (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
         user_error_fn, user_warning_fn, (png_voidp)
         user_mem_ptr, user_malloc_fn, user_free_fn);
 
@@ -1297,7 +1320,7 @@ handling and memory alloc/free functions.
 When libpng encounters an error, it expects to longjmp back
 to your routine.  Therefore, you will need to call setjmp and pass
 your png_jmpbuf(png_ptr).  If you read the file from different
-routines, you will need to update the jmpbuf field every time you enter
+routines, you will need to update the longjmp buffer every time you enter
 a new routine that will call a png_*() function.
 
 See your documentation of setjmp/longjmp for your compiler for more
@@ -1315,6 +1338,9 @@ free any memory.
        return (ERROR);
     }
 
+Pass (png_infopp)NULL instead of &end_info if you didn't create
+an end_info structure.
+
 If you would rather avoid the complexity of setjmp/longjmp issues,
 you can compile libpng with PNG_NO_SETJMP, in which case
 errors will result in a call to PNG_ABORT() which defaults to abort().
@@ -1526,7 +1552,7 @@ large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns.
 Since very few applications really need to process such large images,
 we have imposed an arbitrary 1-million limit on rows and columns.
 Larger images will be rejected immediately with a png_error() call. If
-you wish to override this limit, you can use
+you wish to change this limit, you can use
 
    png_set_user_limits(png_ptr, width_max, height_max);
 
@@ -1536,6 +1562,10 @@ anyway because of potential buffer overflow conditions).
 
 You should put this statement after you create the PNG structure and
 before calling png_read_info(), png_read_png(), or png_process_data().
+
+When writing a PNG datastream, put this statement before calling
+png_write_info() or png_write_png().
+
 If you need to retrieve the limits that are being applied, use
 
    width_max = png_get_user_width_max(png_ptr);
@@ -1566,6 +1596,234 @@ and you can retrieve the limit with
 Any chunks that would cause either of these limits to be exceeded will
 be ignored.
 
+.SS Information about your system
+
+If you intend to display the PNG or to incorporate it in other image data you
+need to tell libpng information about your display or drawing surface so that
+libpng can convert the values in the image to match the display.
+
+From libpng-1.5.4 this information can be set before reading the PNG file
+header.  In earlier versions png_set_gamma() existed but behaved incorrectly if
+called before the PNG file header had been read and png_set_alpha_mode() did not
+exist.
+
+If you need to support versions prior to libpng-1.5.4 test the version number
+and follow the procedures described in the appropriate manual page.
+
+You give libpng the encoding expected by your system expressed as a 'gamma'
+value.  You can also specify a default encoding for the PNG file in
+case the required information is missing from the file.  By default libpng
+assumes that the PNG data matches your system, to keep this default call:
+
+   png_set_gamma(png_ptr, screen_gamma, 1/screen_gamma/*file gamma*/);
+
+or you can use the fixed point equivalent:
+
+   png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma, PNG_FP_1/screen_gamma);
+
+If you don't know the gamma for you system it is probably 2.2 - a good
+approximation to the IEC standard for display systems (sRGB).  If images are
+too contrasty or washed out you got the value wrong - check your system
+documentation!
+
+Many systems permit the system gamma to be changed via a lookup table in the
+display driver, a few systems, including older Macs, change the response by
+default.  As of 1.5.4 three special values are available to handle common
+situations:
+
+   PNG_DEFAULT_sRGB: Indicates that the system conforms to the IEC 61966-2-1
+                     standard.  This matches almost all systems.
+   PNG_GAMMA_MAC_18: Indicates that the system is an older (pre Mac OS 10.6)
+                     Apple Macintosh system with the default settings.
+   PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates that the
+                     system expects data with no gamma encoding.
+
+You would use the linear (unencoded) value if you need to process the pixel
+values further because this avoids the need to decode and reencode each
+component value whenever arithmetic is performed.  A lot of graphics software
+uses linear values for this reason, often with higher precision component values
+to preserve overall accuracy.
+
+The second thing you may need to tell libpng about is how your system handles
+alpha channel information.  Some, but not all, PNG files contain an alpha
+channel.  To display these files correctly you need to compose the data onto a
+suitable background, as described in the PNG specification.
+
+Libpng only supports composing onto a single color (using png_set_background;
+see below.)  Otherwise you must do the composition yourself and, in this case,
+you may need to call png_set_alpha_mode:
+
+   png_set_alpha_mode(png_ptr, mode, screen_gamma);
+
+The screen_gamma value is the same as the argument to png_set_gamma, however how
+it affects the output depends on the mode.  png_set_alpha_mode() sets the file
+gamma default to 1/screen_gamma, so normally you don't need to call
+png_set_gamma.  If you need different defaults call png_set_gamma() before
+png_set_alpha_mode() - if you call it after it will override the settings made
+by png_set_alpha_mode().
+
+The mode is as follows:
+
+    PNG_ALPHA_PNG: The data is encoded according to the PNG specification.  Red,
+green and blue, or gray, components are gamma encoded color
+values and are not premultiplied by the alpha value.  The
+alpha value is a linear measure of the contribution of the
+pixel to the corresponding final output pixel.
+
+You should normally use this format if you intend to perform
+color correction on the color values; most, maybe all, color
+correction software has no handling for the alpha channel and,
+anyway, the math to handle pre-multiplied component values is
+unnecessarily complex.
+
+Before you do any arithmetic on the component values you need
+to remove the gamma encoding and multiply out the alpha
+channel.  See the PNG specification for more detail.  It is
+important to note that when an image with an alpha channel is
+scaled, linear encoded, pre-multiplied component values must
+be used!
+
+The remaining modes assume you don't need to do any further color correction or
+that if you do your color correction software knows all about alpha (it
+probably doesn't!)
+
+    PNG_ALPHA_STANDARD:  The data libpng produces is encoded in the standard way
+assumed by most correctly written graphics software.
+The gamma encoding will be removed by libpng and the
+linear component values will be pre-multiplied by the
+alpha channel.
+
+With this format the final image must be re-encoded to
+match the display gamma before the image is displayed.
+If your system doesn't do that, yet still seems to
+perform arithmetic on the pixels without decoding them,
+it is broken - check out the modes below.
+
+With PNG_ALPHA_STANDARD libpng always produces linear
+component values, whatever screen_gamma you supply.  The
+screen_gamma value is, however, used as a default for
+the file gamma if the PNG file has no gamma information.
+
+If you call png_set_gamma() after png_set_alpha_mode() you
+will override the linear encoding.  Instead the
+pre-multiplied pixel values will be gamma encoded but
+the alpha channel will still be linear.  This may
+actually match the requirements of some broken software,
+but it is unlikely.
+
+While linear 8-bit data is often used it has
+insufficient precision for any image with a reasonable
+dynamic range.  To avoid problems, and if your software
+supports it, use png_set_expand_16() to force all
+components to 16 bits.
+
+    PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD except that
+completely opaque pixels are gamma encoded according to
+the screen_gamma value.  Pixels with alpha less than 1.0
+will still have linear components.
+
+Use this format if you have control over your
+compositing software and do don't do other arithmetic
+(such as scaling) on the data you get from libpng.  Your
+compositing software can simply copy opaque pixels to
+the output but still has linear values for the
+non-opaque pixels.
+
+In normal compositing, where the alpha channel encodes
+partial pixel coverage (as opposed to broad area
+translucency), the inaccuracies of the 8-bit
+representation of non-opaque pixels are irrelevant.
+
+You can also try this format if your software is broken;
+it might look better.
+
+    PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD however all component values,
+including the alpha channel are gamma encoded.  This is
+an appropriate format to try if your software, or more
+likely hardware, is totally broken: if it performs
+linear arithmetic directly on gamma encoded values.
+
+In most cases of broken software or hardware the bug in the final display
+manifests as a subtle halo around composited parts of the image.  You may not
+even perceive this as a halo; the composited part of the image may simply appear
+separate from the background, as though it had been cut out of paper and pasted
+on afterward.
+
+If you don't have to deal with bugs in software or hardware, or if you can fix
+them, there are three recommended ways of using png_set_alpha_mode():
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG,
+       screen_gamma);
+
+You can do color correction on the result (libpng does not currently
+support color correction internally.)  When you handle the alpha channel
+you need to undo the gamma encoding and multiply out the alpha.
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD,
+       screen_gamma);
+   png_set_expand_16(png_ptr);
+
+If you are using the high level interface don't call png_set_expand_16();
+instead pass PNG_TRANSFORM_EXPAND_16 to the interface.
+
+With this mode you can't do color correction, but you can do arithmetic,
+including composition and scaling, on the data without further processing.
+
+   png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED,
+       screen_gamma);
+
+You can avoid the expansion to 16-bit components with this mode, but you
+lose the ability to scale the image or perform other linear arithmetic.
+All you can do is compose the result onto a matching output.  Since this
+mode is libpng specific you also need to write your own composition
+software.
+
+If you don't need, or can't handle, the alpha channel you can call
+png_set_background() to remove it by compositing against a fixed color.  Don't
+call png_set_strip_alpha() to do this - it will leave spurious pixel values in
+transparent parts of this image.
+
+   png_set_background(png_ptr, &background_color,
+       PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);
+
+The background_color is an RGB or grayscale value according to the data format
+libpng will produce for you.  Because you don't yet know the format of the PNG
+file if you call png_set_background at this point you must arrange for the
+format produced by libpng to always have 8-bit or 16-bit components and then
+store the color as an 8-bit or 16-bit color as appropriate.  The color contains
+separate gray and RGB component values, so you can let libpng produce gray or
+RGB output according to the input format, but low bit depth grayscale images
+must always be converted to at least 8-bit format.  (Even low low bit depth
+grayscale images can't have an alpha channel they can have a transparent
+color!)
+
+You set the transforms you need later, either as flags to the high level
+interface or libpng API calls for the low level interface.  For reference the
+settings and API calls required are:
+
+8-bit values:
+   PNG_TRANSFORM_SCALE_16 | PNG_EXPAND
+   png_set_expand(png_ptr); png_set_scale_16(png_ptr);
+
+   If you must get exactly the same inaccurate results
+   produced by default in versions prior to libpng-1.5.4,
+   use PNG_TRANSFORM_STRIP_16 and png_set_strip_16(png_ptr)
+   instead.
+
+16-bit values:
+   PNG_TRANSFORM_EXPAND_16
+   png_set_expand_16(png_ptr);
+
+In either case palette image data will be expanded to RGB.  If you just want
+color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr)
+to the list.
+
+Calling png_set_background before the PNG file header is read will not work
+prior to libpng-1.5.4.  Because the failure may result in unexpected warnings or
+errors it is therefore much safer to call png_set_background after the head has
+been read.  Unfortunately this means that prior to libpng-1.5.4 it cannot be
+used with the high level interface.
+
 .SS The high-level read interface
 
 At this point there are two ways to proceed; through the high-level
@@ -1575,8 +1833,10 @@ the entire image into memory, and (b) the input transformations
 you want to do are limited to the following set:
 
     PNG_TRANSFORM_IDENTITY      No transformation
-    PNG_TRANSFORM_STRIP_16      Strip 16-bit samples to
-                                8 bits
+    PNG_TRANSFORM_SCALE_16      Strip 16-bit samples to
+                                8-bit accurately
+    PNG_TRANSFORM_STRIP_16      Chop 16-bit samples to
+                                8-bit less accurately
     PNG_TRANSFORM_STRIP_ALPHA   Discard the alpha channel
     PNG_TRANSFORM_PACKING       Expand 1, 2 and 4-bit
                                 samples to bytes
@@ -1595,6 +1855,7 @@ you want to do are limited to the following set:
     PNG_TRANSFORM_SWAP_ENDIAN   Byte-swap 16-bit samples
     PNG_TRANSFORM_GRAY_TO_RGB   Expand grayscale samples
                                 to RGB (or GA to RGBA)
+    PNG_TRANSFORM_EXPAND_16     Expand samples to 16 bits
 
 (This excludes setting a background color, doing gamma transformation,
 quantizing, and setting filler.)  If this is the case, simply do this:
@@ -1663,6 +1924,22 @@ call to png_read_info().
 
 This will process all chunks up to but not including the image data.
 
+This also copies some of the data from the PNG file into the decode structure
+for use in later transformations.  Important information copied in is:
+
+1) The PNG file gamma from the gAMA chunk.  This overwrites the default value
+provided by an earlier call to png_set_gamma or png_set_alpha_mode.
+
+2) Prior to libpng-1.5.4 the background color from a bKGd chunk.  This
+damages the information provided by an earlier call to png_set_background
+resulting in expected behavior.  Libpng-1.5.4 no longer does this.
+
+3) The number of significant bits in each component value.  Libpng uses this to
+optimize gamma handling by reducing the internal lookup table sizes.
+
+4) The transparent color information from a tRNS chunk.  This can be modified by
+a later call to png_set_tRNS.
+
 .SS Querying the info structure
 
 Functions are used to get the information from the info_ptr once it
@@ -2026,7 +2303,7 @@ forms:
        converted to microns and back without some loss
        of precision.
 
-For more information, see the png_info definition in png.h and the
+For more information, see the
 PNG specification for chunk contents.  Be careful with trusting
 rowbytes, as some of the transformations could increase the space
 needed to hold a row (expand, filler, gray_to_rgb, etc.).
@@ -2061,17 +2338,20 @@ to handle any special transformations of the image data.  The various
 ways to transform the data will be described in the order that they
 should occur.  This is important, as some of these change the color
 type and/or bit depth of the data, and some others only work on
-certain color types and bit depths.  Even though each transformation
-checks to see if it has data that it can do something with, you should
-make sure to only enable a transformation if it will be valid for the
-data.  For example, don't swap red and blue on grayscale data.
+certain color types and bit depths.
+
+Transformations you request are ignored if they don't have any meaning for a
+particular input data format.  However some transformations can have an effect
+as a result of a previous transformation.  If you specify a contradictory set of
+transformations, for example both adding and removing the alpha channel, you
+cannot predict the final result.
 
-The colors used for the background and transparency values should be
-supplied in the same format/depth as the current image data.  They
-are stored in the same format/depth as the image data in a bKGD or tRNS
-chunk, so this is what libpng expects for this data.  The colors are
-transformed to keep in sync with the image data when an application
-calls the png_read_update_info() routine (see below).
+The color used for the transparency values should be supplied in the same
+format/depth as the current image data.  It is stored in the same format/depth
+as the image data in a tRNS chunk, so this is what libpng expects for this data.
+
+The color used for the background value depends on the need_expand argument as
+described below.
 
 Data will be decoded into the supplied row buffers packed into bytes
 unless the library has been told to transform it into another format.
@@ -2081,12 +2361,12 @@ byte, unless png_set_packing() is called.  8-bit RGB data will be stored
 in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha()
 is called to insert filler bytes, either before or after each RGB triplet.
 16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant
-byte of the color value first, unless png_set_strip_16() is called to
+byte of the color value first, unless png_set_scale_16() is called to
 transform it to regular RGB RGB triplets, or png_set_filler() or
 png_set_add alpha() is called to insert filler bytes, either before or
 after each RRGGBB triplet.  Similarly, 8-bit or 16-bit grayscale data can
-be modified with
-png_set_filler(), png_set_add_alpha(), or png_set_strip_16().
+be modified with png_set_filler(), png_set_add_alpha(), png_set_strip_16(),
+or png_set_scale_16().
 
 The following code transforms grayscale images of less than 8 to 8 bits,
 changes paletted images to RGB, and adds a full alpha channel if there is
@@ -2120,27 +2400,25 @@ severe accuracy loss.
       png_set_expand_16(png_ptr);
 
 PNG can have files with 16 bits per channel.  If you only can handle
-8 bits per channel, this will strip the pixels down to 8 bit.
+8 bits per channel, this will strip the pixels down to 8-bit.
 
     if (bit_depth == 16)
-       png_set_strip_16(png_ptr);
+       png_set_scale_16(png_ptr);
 
-If, for some reason, you don't need the alpha channel on an image,
-and you want to remove it rather than combining it with the background
-(but the image author certainly had in mind that you *would* combine
-it with the background, so that's what you should probably do):
+If you need to process the alpha channel on the image separately from the image
+data (for example if you convert it to a bitmap mask) it is possible to have
+libpng strip the channel leaving just RGB or gray data:
 
     if (color_type & PNG_COLOR_MASK_ALPHA)
        png_set_strip_alpha(png_ptr);
 
-See below for png_set_background(), which does the correct composition on a
-single opaque color.  This is probably what you should do in all cases rather
-than use png_set_strip_alpha() - unless you know for sure that it is the wrong
-thing to do.
+If you strip the alpha channel you need to find some other way of dealing with
+the information.  If, instead, you want to convert the image to an opaque
+version with no alpha channel use png_set_background; see below.
 
 As of libpng version 1.5.2, almost all useful expansions are supported, the
-major ommissions are convertion of grayscale to indexed images (which can be
-done trivially in the application) and convertion of indexed to grayscale (which
+major ommissions are conversion of grayscale to indexed images (which can be
+done trivially in the application) and conversion of indexed to grayscale (which
 can be done by a trivial manipulation of the palette.)
 
 In the following table, the 01 means grayscale with depth<8, 31 means
@@ -2177,8 +2455,7 @@ Within the matrix,
          png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() if there
          is no transparency in the original or the final format).
      "C" means the transformation is obtained by png_set_gray_to_rgb().
-     "G" means the transformation is obtained by png_set_rgb_to_gray() or
-         png_set_rgb_to_Y().
+     "G" means the transformation is obtained by png_set_rgb_to_gray().
      "P" means the transformation is obtained by
          png_set_expand_palette_to_rgb().
      "p" means the transformation is obtained by png_set_packing().
@@ -2270,8 +2547,8 @@ with alpha.
 
     if (color_type == PNG_COLOR_TYPE_RGB ||
         color_type == PNG_COLOR_TYPE_RGB_ALPHA)
-       png_set_rgb_to_gray_fixed(png_ptr, error_action,
-           int red_weight, int green_weight);
+       png_set_rgb_to_gray(png_ptr, error_action, double red_weight,
+          double green_weight);
 
     error_action = 1: silently do the conversion
 
@@ -2284,122 +2561,89 @@ with alpha.
                       image has any pixel where
                       red != green or red != blue
 
-    red_weight:       weight of red component times 100000
+    red_weight:       weight of red component
 
-    green_weight:     weight of green component times 100000
+    green_weight:     weight of green component
                       If either weight is negative, default
-                      weights (21268, 71514) are used.
+                      weights are used.
+
+In the corresponding fixed point API the red_weight and green_weight values are
+simply scaled by 100,000:
+
+    png_set_rgb_to_gray(png_ptr, error_action, png_fixed_point red_weight,
+       png_fixed_point green_weight);
 
 If you have set error_action = 1 or 2, you can
 later check whether the image really was gray, after processing
 the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
 It will return a png_byte that is zero if the image was gray or
-1 if there were any non-gray pixels.  bKGD and sBIT data
+1 if there were any non-gray pixels.  Background and sBIT data
 will be silently converted to grayscale, using the green channel
-data, regardless of the error_action setting.
+data for sBIT, regardless of the error_action setting.
 
-With red_weight+green_weight<=100000,
-the normalized graylevel is computed:
+The default values come from the PNG file cHRM chunk if present, otherwise the
+defaults correspond to the ITU-R recommendation 709, and also the sRGB color
+space, as recommended in the Charles Poynton's Colour FAQ,
+<http://www.poynton.com/>, in section 9:
 
-    int rw = red_weight * 65536;
-    int gw = green_weight * 65536;
-    int bw = 65536 - (rw + gw);
-    gray = (rw*red + gw*green + bw*blue)/65536;
-
-The default values approximate those recommended in the Charles
-Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
-Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net>
+   <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9>
 
     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
 
-Libpng approximates this with integers scaled by 32768:
-
-    Y = (6968 * R + 23434 * G + 2366 * B)/32768
-
 The calculation is done in a linear colorspace, if the image gamma
 can be determined.
 
-If you have a grayscale and you are using png_set_expand_gray_1_2_4_to_8(),
-png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to
-a higher bit-depth, you must either supply the background color as a gray
-value at the original file bit-depth (need_expand = 1) or else supply the
-background color as an RGB triplet at the final, expanded bit depth
-(need_expand = 0).  Similarly, if you are reading a paletted image, you
-must either supply the background color as a palette index (need_expand = 1)
-or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+The png_set_background() function has been described already, it tells libpng to
+composite images with alpha or simple transparency against the supplied
+background color.  For compatibility with versions of libpng earlier than
+libpng-1.5.4 it is recommended that you call the function after reading the file
+header, even if you don't want to use the color in a bKGD chunk, if one exists.
+
+If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page).  You
+need to tell libpng how the color is represented, both the format of the
+component values in the color (the number of bits) and the gamme encoding of the
+color.  The function takes two arguments, background_gamma_mode and need_expand
+to convey this information, however only two combinations are like to be useful:
 
     png_color_16 my_background;
     png_color_16p image_background;
 
     if (png_get_bKGD(png_ptr, info_ptr, &image_background))
        png_set_background(png_ptr, image_background,
-           PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+           PNG_BACKGROUND_GAMMA_FILE, 1/*needs to be expanded*/, 1);
     else
        png_set_background(png_ptr, &my_background,
-           PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+           PNG_BACKGROUND_GAMMA_SCREEN, 0/*do not expand*/, 1);
 
-The png_set_background() function tells libpng to composite images
-with alpha or simple transparency against the supplied background
-color.  If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
-you may use this color, or supply another color more suitable for
-the current display (e.g., the background color from a web page).  You
-need to tell libpng whether the color is in the gamma space of the
-display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
-(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
-that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
-know why anyone would use this, but it's here).
-
-To properly display PNG images on any kind of system, the application needs
-to know what the display gamma is.  Ideally, the user will know this, and
-the application will allow them to set it.  One method of allowing the user
-to set the display gamma separately for each system is to check for a
-SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be
-correctly set.
-
-Note that display_gamma is the overall gamma correction required to produce
-pleasing results, which depends on the lighting conditions in the surrounding
-environment.  In a dim or brightly lit room, no compensation other than
-the physical gamma exponent of the monitor is needed, while in a dark room
-a slightly smaller exponent is better.
-
-   double gamma, screen_gamma;
-
-   if (/* We have a user-defined screen
-       gamma value */)
-   {
-      screen_gamma = user_defined_screen_gamma;
-   }
 
-   /* One way that applications can share the same
-      screen gamma value */
-   else if ((gamma_str = getenv("SCREEN_GAMMA"))
-      != NULL)
-   {
-      screen_gamma = (double)atof(gamma_str);
-   }
+The second call was described above - my_background is in the format of the
+final, display, output produced by libpng.  Because you now know the format of
+the PNG it is possible to avoid the need to choose either 8-bit or 16-bit
+output and to retain palette images (the palette colors will be modified
+appropriately and the tRNS chunk removed.)  However, if you are doing this,
+take great care not to ask for transformations without checking first that
+they apply!
 
-   /* If we don't have another value */
-   else
-   {
-      screen_gamma = 2.2; /* A good guess for a
-           PC monitor in a bright office or a dim room */
+In the first call the background color has the original bit depth and color type
+of the PNG file.  So, for palette images the color is supplied as a palette
+index and for low bit greyscale images the color is a reduced bit value in
+image_background->gray.
 
-      screen_gamma = 2.0; /* A good guess for a
-           PC monitor in a dark room */
+If you didn't call png_set_gamma() before reading the file header, for example
+if you need your code to remain compatible with older versions of libpng prior
+to libpng-1.5.4, this is the place to call it.
 
-      screen_gamma = 1.7 or 1.0;  /* A good
-           guess for Mac systems */
-   }
+Do not call it if you called png_set_alpha_mode(); doing so will damage the
+settings put in place by png_set_alpha_mode().  (If png_set_alpha_mode() is
+supported then you can certainly do png_set_gamma() before reading the PNG
+header.)
 
-The functions png_set_gamma() and its fixed point equivalent
-png_set_gamma_fixed() handle gamma transformations of the data.
-Pass both the file gamma and the current screen_gamma.  If the file does
-not have a gamma value, you can pass one anyway if you have an idea what
-it is (usually 0.45455 is a good guess for GIF images on PCs).  Note
-that file gammas are inverted from screen gammas.  See the discussions
-on gamma in the PNG specification for an excellent description of what
-gamma is, and why all applications should support it.  It is strongly
-recommended that PNG viewers support gamma correction.
+This API unconditionally sets the screen and file gamma values, so it will
+override the value in the PNG file unless it is called before the PNG file
+reading starts.  For this reason you must always call it with the PNG file
+value when you call it in this position:
 
    if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
       png_set_gamma(png_ptr, screen_gamma, file_gamma);
@@ -2455,7 +2699,7 @@ This function can also be used to invert grayscale and gray-alpha images:
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
       png_set_invert_mono(png_ptr);
 
-PNG files store 16 bit pixels in network byte order (big-endian,
+PNG files store 16-bit pixels in network byte order (big-endian,
 ie. most significant bits first).  This code changes the storage to the
 other way (little-endian, i.e. least significant bits first, the
 way PCs store them):
@@ -2747,15 +2991,39 @@ low-level interface, you can finish reading the file.  If you are
 interested in comments or time, which may be stored either before or
 after the image data, you should pass the separate png_info struct if
 you want to keep the comments from before and after the image
-separate.  If you are not interested, you can pass NULL.
+separate.
+
+    png_infop end_info = png_create_info_struct(png_ptr);
+
+    if (!end_info)
+    {
+       png_destroy_read_struct(&png_ptr, &info_ptr,
+           (png_infopp)NULL);
+       return (ERROR);
+    }
 
    png_read_end(png_ptr, end_info);
 
+If you are not interested, you should still call png_read_end()
+but you can pass NULL, avoiding the need to create an end_info structure.
+
+   png_read_end(png_ptr, (png_infop)NULL);
+
+If you don't call png_read_end(), then your file pointer will be
+left pointing to the first chunk after the last IDAT, which is probably
+not what you want if you expect to read something beyond the end of
+the PNG datastream.
+
 When you are done, you can free all memory allocated by libpng like this:
 
    png_destroy_read_struct(&png_ptr, &info_ptr,
        &end_info);
 
+or, if you didn't create an end_info structure,
+
+   png_destroy_read_struct(&png_ptr, &info_ptr,
+       (png_infopp)NULL);
+
 It is also possible to individually free the info_ptr members that
 point to libpng-allocated storage with the following function:
 
@@ -3218,11 +3486,11 @@ with zlib) for details on the compression levels.
 
     #include zlib.h
 
-    /* set the zlib compression level */
+    /* Set the zlib compression level */
     png_set_compression_level(png_ptr,
         Z_BEST_COMPRESSION);
 
-    /* set other zlib parameters */
+    /* Set other zlib parameters for compressing IDAT */
     png_set_compression_mem_level(png_ptr, 8);
     png_set_compression_strategy(png_ptr,
         Z_DEFAULT_STRATEGY);
@@ -3230,7 +3498,15 @@ with zlib) for details on the compression levels.
     png_set_compression_method(png_ptr, 8);
     png_set_compression_buffer_size(png_ptr, 8192)
 
-extern PNG_EXPORT(void,png_set_zbuf_size)
+    /* Set zlib parameters for text compression
+     * If you don't call these, the parameters
+     * fall back on those defined for IDAT chunks
+     */
+    png_set_text_compression_mem_level(png_ptr, 8);
+    png_set_text_compression_strategy(png_ptr,
+        Z_DEFAULT_STRATEGY);
+    png_set_text_compression_window_bits(png_ptr, 15);
+    png_set_text_compression_method(png_ptr, 8);
 
 .SS Setting the contents of info for output
 
@@ -3736,7 +4012,7 @@ is required by PNG.
 
     png_set_shift(png_ptr, &sig_bit);
 
-PNG files store 16 bit pixels in network byte order (big-endian,
+PNG files store 16-bit pixels in network byte order (big-endian,
 ie. most significant bits first).  This code would be used if they are
 supplied the other way (little-endian, i.e. least significant bits
 first, the way PCs store them):
@@ -4152,7 +4428,7 @@ the simpler ones to get an idea of how they work.  Try to find a similar
 transformation to the one you want to add and copy off of it.  More details
 can be found in the comments inside the code itself.
 
-.SS Configuring for 16 bit platforms
+.SS Configuring for 16-bit platforms
 
 You will want to look into zconf.h to tell zlib (and thus libpng) that
 it cannot allocate more then 64K at a time.  Even if you can, the memory
@@ -4658,7 +4934,8 @@ The png_zalloc() function no longer zeroes out the memory that it
 allocates.
 
 Support for dithering was disabled by default in libpng-1.4.0, because
-been well tested and doesn't actually "dither".  The code was not
+it has not been well tested and doesn't actually "dither".
+The code was not
 removed, however, and could be enabled by building libpng with
 PNG_READ_DITHER_SUPPORTED defined.  In libpng-1.4.2, this support
 was reenabled, but the function was renamed png_set_quantize() to
@@ -4719,8 +4996,9 @@ absolutely necessary) interlace an image.
 libpng 1.5.0 adds an API png_longjmp(png_ptr, value).  This API calls
 the application-provided png_longjmp_ptr on the internal, but application
 initialized, jmpbuf.  It is provided as a convenience to avoid the need
-to use the png_jmpbuf macro, which had the unnecessary side effect of
-resetting the internal png_longjmp_ptr value.
+initialized, longjmp buffer.  It is provided as a convenience to avoid
+the need to use the png_jmpbuf macro, which had the unnecessary side
+effect of resetting the internal png_longjmp_ptr value.
 
 libpng 1.5.0 includes a complete fixed point API.  By default this is
 present along with the corresponding floating point API.  In general the
@@ -4774,6 +5052,25 @@ PNG_NO_USE_READ_MACROS before including png.h.  Notice that this is
 only supported from 1.5.0 -defining PNG_NO_USE_READ_MACROS prior to 1.5.0
  will lead to a link failure.
 
+Prior to libpng-1.5.4, the zlib compressor used the same set of parameters
+when compressing the IDAT data and textual data such as zTXt and iCCP.
+In libpng-1.5.4 we reinitialized the zlib stream for each type of data.
+We added five png_set_text_*() functions for setting the parameters to
+use with textual data.
+
+Prior to libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+option was off by default, and slightly inaccurate scaling occurred.
+This option can no longer be turned off, and the choice of accurate
+or inaccurate 16-to-8 scaling is by using the new png_set_scale_16_to_8()
+API for accurate scaling or the old png_set_strip_16_to_8() API for simple
+chopping.
+
+Prior to libpng-1.5.4, the png_set_user_limits() function could only be
+used to reduce the width and height limits from the value of
+PNG_USER_WIDTH_MAX and PNG_USER_HEIGHT_MAX, although this document said
+that it could be used to override them.  Now this function will reduce or
+increase the limits.
+
 B. Changes to the build and configuration of libpng
 
 Details of internal changes to the library code can be found in the CHANGES
@@ -5082,13 +5379,13 @@ Other rules can be inferred by inspecting the libpng source.
 
 .SH XIV. Y2K Compliance in libpng
 
-March 31, 2011
+July 7, 2011
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
 
 This is your unofficial assurance that libpng from version 0.71 and
-upward through 1.5.2 are Y2K compliant.  It is my belief that earlier
+upward through 1.5.4 are Y2K compliant.  It is my belief that earlier
 versions were also Y2K compliant.
 
 Libpng only has three year fields.  One is a 2-byte unsigned integer that
@@ -5277,6 +5574,13 @@ the first widely used release:
  1.5.2beta01-03      15    10502  15.so.15.2[.0]
  1.5.2rc01-03        15    10502  15.so.15.2[.0]
  1.5.2               15    10502  15.so.15.2[.0]
+ 1.5.3beta01-10      15    10503  15.so.15.3[.0]
+ 1.5.3rc01-02        15    10503  15.so.15.3[.0]
+ 1.5.3beta11         15    10503  15.so.15.3[.0]
+ 1.5.3 [omitted]
+ 1.5.4beta01-08      15    10504  15.so.15.4[.0]
+ 1.5.4rc01           15    10504  15.so.15.4[.0]
+ 1.5.4               15    10504  15.so.15.4[.0]
 
 Henceforth the source version will match the shared-library minor
 and patch numbers; the shared-library major version number will be
@@ -5333,7 +5637,7 @@ possible without all of you.
 
 Thanks to Frank J. T. Wojcik for helping with the documentation.
 
-Libpng version 1.5.2 - March 31, 2011:
+Libpng version 1.5.4 - July 7, 2011:
 Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
 Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net).
 
@@ -5356,7 +5660,7 @@ this sentence.
 
 This code is released under the libpng license.
 
-libpng versions 1.2.6, August 15, 2004, through 1.5.2, March 31, 2011, are
+libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
 Copyright (c) 2004,2006-2007 Glenn Randers-Pehrson, and are
 distributed according to the same disclaimer and license as libpng-1.2.5
 with the following individual added to the list of Contributing Authors
@@ -5455,7 +5759,7 @@ certification mark of the Open Source Initiative.
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-March 31, 2011
+July 7, 2011
 
 .\" end of man page
 
index cc7f13870aea7396ab13b96492dd89bac6449947..33c9ad3929c6b3b70d050ca6e3d24994c990a1c8 100644 (file)
@@ -1,6 +1,6 @@
-.TH LIBPNGPF 3 "March 31, 2011"
+.TH LIBPNGPF 3 "July 7, 2011"
 .SH NAME
-libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
+libpng \- Portable Network Graphics (PNG) Reference Library 1.5.4
 (private functions)
 .SH SYNOPSIS
 \fB#include \fI"pngpriv.h"
@@ -18,11 +18,9 @@ libpng \- Portable Network Graphics (PNG) Reference Library 1.5.2
 \fI\fB
 
 .SH DESCRIPTION
-The functions previously listed here are  used privately by libpng
+The functions previously listed here are used privately by libpng
 and are not recommended for use by applications.  They are
-not "exported" to applications using shared libraries.  They
-are listed alphabetically here as an aid to libpng maintainers.
-See pngpriv.h for more information on these functions.
+not "exported" to applications using shared libraries.
 
 .SH SEE ALSO
 .BR "png"(5), " libpng"(3), " zlib"(3), " deflate"(5), " " and " zlib"(5)
index f4ccec0a94c9c24fe34aaa75a3545fdeca60b060..0fca76eca2fbd0b2018c82fb62c061bef4b549b2 100644 (file)
@@ -1,4 +1,4 @@
-.TH PNG 5 "March 31, 2011"
+.TH PNG 5 "July 7, 2011"
 .SH NAME
 png \- Portable Network Graphics (PNG) format
 .SH DESCRIPTION
index 7d09b0dbd2104d5a0f1da7090b7eb0bf9e549e9c..eed31361955d6be61834124ed9bb082973c0fdd3 100644 (file)
@@ -1,7 +1,7 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -14,7 +14,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_2 Your_png_h_is_not_version_1_5_2;
+typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4;
 
 /* Tells libpng that we have already handled the first "num_bytes" bytes
  * of the PNG file signature.  If the PNG data is embedded into another
@@ -137,6 +137,61 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
       png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
 }
 
+/* Check a user supplied version number, called from both read and write
+ * functions that create a png_struct
+ */
+int
+png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver)
+{
+   if (user_png_ver)
+   {
+      int i = 0;
+
+      do
+      {
+         if (user_png_ver[i] != png_libpng_ver[i])
+            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+      } while (png_libpng_ver[i++]);
+   }
+
+   else
+      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+
+   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+   {
+     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+      * we must recompile any applications that use any older library version.
+      * For versions after libpng 1.0, we will be compatible, so we need
+      * only check the first digit.
+      */
+      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+          (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
+          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+      {
+#ifdef PNG_WARNINGS_SUPPORTED
+         size_t pos = 0;
+         char m[128];
+
+         pos = png_safecat(m, sizeof m, pos, "Application built with libpng-");
+         pos = png_safecat(m, sizeof m, pos, user_png_ver);
+         pos = png_safecat(m, sizeof m, pos, " but running with ");
+         pos = png_safecat(m, sizeof m, pos, png_libpng_ver);
+
+         png_warning(png_ptr, m);
+#endif
+
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+         png_ptr->flags = 0;
+#endif
+
+         return 0;
+      }
+   }
+
+   /* Success return. */
+   return 1;
+}
+
 /* Allocate the memory for an info_struct for the application.  We don't
  * really need the png_ptr, but it could potentially be useful in the
  * future.  This should be used in favour of malloc(png_sizeof(png_info))
@@ -291,12 +346,10 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
    /* Free any sCAL entry */
    if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
    {
-#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
       png_free(png_ptr, info_ptr->scal_s_width);
       png_free(png_ptr, info_ptr->scal_s_height);
       info_ptr->scal_s_width = NULL;
       info_ptr->scal_s_height = NULL;
-#endif
       info_ptr->valid &= ~PNG_INFO_sCAL;
    }
 #endif
@@ -518,28 +571,37 @@ png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime)
    if (png_ptr == NULL)
       return (NULL);
 
-   if (png_ptr->time_buffer == NULL)
    {
-      png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
-         png_sizeof(char)));
+      size_t pos = 0;
+      char number_buf[5]; /* enough for a four digit year */
+
+#     define APPEND_STRING(string)\
+         pos = png_safecat(png_ptr->time_buffer, sizeof png_ptr->time_buffer,\
+            pos, (string))
+#     define APPEND_NUMBER(format, value)\
+         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
+#     define APPEND(ch)\
+         if (pos < (sizeof png_ptr->time_buffer)-1)\
+            png_ptr->time_buffer[pos++] = (ch)
+
+      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day % 32);
+      APPEND(' ');
+      APPEND_STRING(short_months[(ptime->month - 1) % 12]);
+      APPEND(' ');
+      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
+      APPEND(' ');
+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour % 24);
+      APPEND(':');
+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute % 60);
+      APPEND(':');
+      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second % 61);
+      APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
+
+#     undef APPEND
+#     undef APPEND_NUMBER
+#     undef APPEND_STRING
    }
 
-#    ifdef USE_FAR_KEYWORD
-   {
-      char near_time_buf[29];
-      png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000",
-          ptime->day % 32, short_months[(ptime->month - 1) % 12],
-          ptime->year, ptime->hour % 24, ptime->minute % 60,
-          ptime->second % 61);
-      png_memcpy(png_ptr->time_buffer, near_time_buf,
-          29*png_sizeof(char));
-   }
-#    else
-   png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000",
-       ptime->day % 32, short_months[(ptime->month - 1) % 12],
-       ptime->year, ptime->hour % 24, ptime->minute % 60,
-       ptime->second % 61);
-#    endif
    return png_ptr->time_buffer;
 }
 #  endif /* PNG_TIME_RFC1123_SUPPORTED */
@@ -555,13 +617,13 @@ png_get_copyright(png_const_structp png_ptr)
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-     "libpng version 1.5.2 - March 31, 2011" PNG_STRING_NEWLINE \
+     "libpng version 1.5.4 - July 7, 2011" PNG_STRING_NEWLINE \
      "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
      PNG_STRING_NEWLINE;
 #  else
-      return "libpng version 1.5.2 - March 31, 2011\
+      return "libpng version 1.5.4 - July 7, 2011\
       Copyright (c) 1998-2011 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -681,6 +743,13 @@ png_check_cHRM_fixed(png_structp png_ptr,
    if (png_ptr == NULL)
       return 0;
 
+   /* (x,y,z) values are first limited to 0..100000 (PNG_FP_1), the white
+    * y must also be greater than 0.  To test for the upper limit calculate
+    * (PNG_FP_1-y) - x must be <= to this for z to be >= 0 (and the expression
+    * cannot overflow.)  At this point we know x and y are >= 0 and (x+y) is
+    * <= PNG_FP_1.  The previous test on PNG_MAX_UINT_31 is removed because it
+    * pointless (and it produces compiler warnings!)
+    */
    if (white_x < 0 || white_y <= 0 ||
          red_x < 0 ||   red_y <  0 ||
        green_x < 0 || green_y <  0 ||
@@ -690,38 +759,26 @@ png_check_cHRM_fixed(png_structp png_ptr,
         "Ignoring attempt to set negative chromaticity value");
       ret = 0;
    }
-   if (white_x > (png_fixed_point)PNG_UINT_31_MAX ||
-       white_y > (png_fixed_point)PNG_UINT_31_MAX ||
-         red_x > (png_fixed_point)PNG_UINT_31_MAX ||
-         red_y > (png_fixed_point)PNG_UINT_31_MAX ||
-       green_x > (png_fixed_point)PNG_UINT_31_MAX ||
-       green_y > (png_fixed_point)PNG_UINT_31_MAX ||
-        blue_x > (png_fixed_point)PNG_UINT_31_MAX ||
-        blue_y > (png_fixed_point)PNG_UINT_31_MAX )
-   {
-      png_warning(png_ptr,
-        "Ignoring attempt to set chromaticity value exceeding 21474.83");
-      ret = 0;
-   }
-   if (white_x > 100000L - white_y)
+   /* And (x+y) must be <= PNG_FP_1 (so z is >= 0) */
+   if (white_x > PNG_FP_1 - white_y)
    {
       png_warning(png_ptr, "Invalid cHRM white point");
       ret = 0;
    }
 
-   if (red_x > 100000L - red_y)
+   if (red_x > PNG_FP_1 - red_y)
    {
       png_warning(png_ptr, "Invalid cHRM red point");
       ret = 0;
    }
 
-   if (green_x > 100000L - green_y)
+   if (green_x > PNG_FP_1 - green_y)
    {
       png_warning(png_ptr, "Invalid cHRM green point");
       ret = 0;
    }
 
-   if (blue_x > 100000L - blue_y)
+   if (blue_x > PNG_FP_1 - blue_y)
    {
       png_warning(png_ptr, "Invalid cHRM blue point");
       ret = 0;
@@ -763,7 +820,7 @@ png_check_IHDR(png_structp png_ptr,
    }
 
 #  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX)
+   if (width > png_ptr->user_width_max)
 
 #  else
    if (width > PNG_USER_WIDTH_MAX)
@@ -774,7 +831,7 @@ png_check_IHDR(png_structp png_ptr,
    }
 
 #  ifdef PNG_SET_USER_LIMITS_SUPPORTED
-   if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX)
+   if (height > png_ptr->user_height_max)
 #  else
    if (height > PNG_USER_HEIGHT_MAX)
 #  endif
@@ -889,16 +946,9 @@ png_check_IHDR(png_structp png_ptr,
 /* Check an ASCII formated floating point value, see the more detailed
  * comments in pngpriv.h
  */
-/* The following is used internally to preserve the 'valid' flag */
+/* The following is used internally to preserve the sticky flags */
 #define png_fp_add(state, flags) ((state) |= (flags))
-#define png_fp_set(state, value)\
-   ((state) = (value) | ((state) & PNG_FP_WAS_VALID))
-
-/* Internal type codes: bits above the base state! */
-#define PNG_FP_SIGN   0  /* [+-] */
-#define PNG_FP_DOT    4  /* . */
-#define PNG_FP_DIGIT  8  /* [0123456789] */
-#define PNG_FP_E     12  /* [Ee] */
+#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))
 
 int /* PRIVATE */
 png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
@@ -911,55 +961,55 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
    {
       int type;
       /* First find the type of the next character */
+      switch (string[i])
       {
-         char ch = string[i];
-
-         if (ch >= 48 && ch <= 57)
-            type = PNG_FP_DIGIT;
-
-         else switch (ch)
-         {
-         case 43: case 45:  type = PNG_FP_SIGN;  break;
-         case 46:           type = PNG_FP_DOT;   break;
-         case 69: case 101: type = PNG_FP_E;     break;
-         default:           goto PNG_FP_End;
-         }
+      case 43:  type = PNG_FP_SAW_SIGN;                   break;
+      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;
+      case 46:  type = PNG_FP_SAW_DOT;                    break;
+      case 48:  type = PNG_FP_SAW_DIGIT;                  break;
+      case 49: case 50: case 51: case 52:
+      case 53: case 54: case 55: case 56:
+      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;
+      case 69:
+      case 101: type = PNG_FP_SAW_E;                      break;
+      default:  goto PNG_FP_End;
       }
 
       /* Now deal with this type according to the current
        * state, the type is arranged to not overlap the
        * bits of the PNG_FP_STATE.
        */
-      switch ((state & PNG_FP_STATE) + type)
+      switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY))
       {
-      case PNG_FP_INTEGER + PNG_FP_SIGN:
+      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:
          if (state & PNG_FP_SAW_ANY)
             goto PNG_FP_End; /* not a part of the number */
 
-         png_fp_add(state, PNG_FP_SAW_SIGN);
+         png_fp_add(state, type);
          break;
 
-      case PNG_FP_INTEGER + PNG_FP_DOT:
+      case PNG_FP_INTEGER + PNG_FP_SAW_DOT:
          /* Ok as trailer, ok as lead of fraction. */
          if (state & PNG_FP_SAW_DOT) /* two dots */
             goto PNG_FP_End;
 
          else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */
-            png_fp_add(state, PNG_FP_SAW_DOT);
+            png_fp_add(state, type);
 
          else
-            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
+            png_fp_set(state, PNG_FP_FRACTION | type);
 
          break;
 
-      case PNG_FP_INTEGER + PNG_FP_DIGIT:
+      case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT:
          if (state & PNG_FP_SAW_DOT) /* delayed fraction */
             png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
 
-         png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
+         png_fp_add(state, type | PNG_FP_WAS_VALID);
 
          break;
-      case PNG_FP_INTEGER + PNG_FP_E:
+
+      case PNG_FP_INTEGER + PNG_FP_SAW_E:
          if ((state & PNG_FP_SAW_DIGIT) == 0)
             goto PNG_FP_End;
 
@@ -967,17 +1017,17 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
 
          break;
 
-   /* case PNG_FP_FRACTION + PNG_FP_SIGN:
-         goto PNG_FP_End; ** no sign in exponent */
+   /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN:
+         goto PNG_FP_End; ** no sign in fraction */
 
-   /* case PNG_FP_FRACTION + PNG_FP_DOT:
+   /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT:
          goto PNG_FP_End; ** Because SAW_DOT is always set */
 
-      case PNG_FP_FRACTION + PNG_FP_DIGIT:
-         png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
+      case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT:
+         png_fp_add(state, type | PNG_FP_WAS_VALID);
          break;
 
-      case PNG_FP_FRACTION + PNG_FP_E:
+      case PNG_FP_FRACTION + PNG_FP_SAW_E:
          /* This is correct because the trailing '.' on an
           * integer is handled above - so we can only get here
           * with the sequence ".E" (with no preceding digits).
@@ -989,7 +1039,7 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
 
          break;
 
-      case PNG_FP_EXPONENT + PNG_FP_SIGN:
+      case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN:
          if (state & PNG_FP_SAW_ANY)
             goto PNG_FP_End; /* not a part of the number */
 
@@ -997,15 +1047,15 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
 
          break;
 
-   /* case PNG_FP_EXPONENT + PNG_FP_DOT:
+   /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT:
          goto PNG_FP_End; */
 
-      case PNG_FP_EXPONENT + PNG_FP_DIGIT:
-         png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
+      case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT:
+         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);
 
          break;
 
-   /* case PNG_FP_EXPONEXT + PNG_FP_E:
+   /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E:
          goto PNG_FP_End; */
 
       default: goto PNG_FP_End; /* I.e. break 2 */
@@ -1033,8 +1083,11 @@ png_check_fp_string(png_const_charp string, png_size_t size)
    int        state=0;
    png_size_t char_index=0;
 
-   return png_check_fp_number(string, size, &state, &char_index) &&
-      (char_index == size || string[char_index] == 0);
+   if (png_check_fp_number(string, size, &state, &char_index) &&
+      (char_index == size || string[char_index] == 0))
+      return state /* must be non-zero - see above */;
+
+   return 0; /* i.e. fail */
 }
 #endif /* pCAL or sCAL */
 
@@ -1102,7 +1155,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
       if (fp < 0)
       {
          fp = -fp;
-         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1*/
+         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */
          --size;
       }
 
@@ -1329,7 +1382,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
              */
             size -= cdigits;
 
-            *ascii++ = 69, --size;    /* 'E': PLUS 1 TOTAL 2+precision*/
+            *ascii++ = 69, --size;    /* 'E': PLUS 1 TOTAL 2+precision */
             if (exp_b10 < 0)
             {
                *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
@@ -1401,7 +1454,7 @@ png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
 
       if (num <= 0x80000000U) /* else overflowed */
       {
-         unsigned int ndigits = 0, first = 16/*flag value*/;
+         unsigned int ndigits = 0, first = 16 /* flag value */;
          char digits[10];
 
          while (num)
@@ -1495,7 +1548,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
          r /= divisor;
          r = floor(r+.5);
 
-         /* A png_fixed_point is a 32 bit integer. */
+         /* A png_fixed_point is a 32-bit integer. */
          if (r <= 2147483647. && r >= -2147483648.)
          {
             *res = (png_fixed_point)r;
@@ -1540,7 +1593,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
 
          if (s32 < D) /* else overflow */
          {
-            /* s32.s00 is now the 64 bit product, do a standard
+            /* s32.s00 is now the 64-bit product, do a standard
              * division, we know that s32 < D, so the maximum
              * required shift is 31.
              */
@@ -1683,7 +1736,7 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b)
  * 2010: moved from pngset.c) */
 /*
  *    Multiply two 32-bit numbers, V1 and V2, using 32-bit
- *    arithmetic, to produce a 64 bit result in the HI/LO words.
+ *    arithmetic, to produce a 64-bit result in the HI/LO words.
  *
  *                  A B
  *                x C D
@@ -1727,17 +1780,17 @@ png_64bit_product (long v1, long v2, unsigned long *hi_product,
 /* Fixed point gamma.
  *
  * To calculate gamma this code implements fast log() and exp() calls using only
- * fixed point arithmetic.  This code has sufficient precision for either 8 or
- * 16 bit sample values.
+ * fixed point arithmetic.  This code has sufficient precision for either 8-bit
+ * or 16-bit sample values.
  *
  * The tables used here were calculated using simple 'bc' programs, but C double
  * precision floating point arithmetic would work fine.  The programs are given
  * at the head of each table.
  *
- * 8 bit log table
+ * 8-bit log table
  *   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
- *   255, so it's the base 2 logarithm of a normalized 8 bit floating point
- *   mantissa.  The numbers are 32 bit fractions.
+ *   255, so it's the base 2 logarithm of a normalized 8-bit floating point
+ *   mantissa.  The numbers are 32-bit fractions.
  */
 static png_uint_32
 png_8bit_l2[128] =
@@ -1768,10 +1821,10 @@ png_8bit_l2[128] =
    172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
    24347096U, 0U
 #if 0
-   /* The following are the values for 16 bit tables - these work fine for the 8
-    * bit conversions but produce very slightly larger errors in the 16 bit log
-    * (about 1.2 as opposed to 0.7 absolute error in the final value).  To use
-    * these all the shifts below must be adjusted appropriately.
+   /* The following are the values for 16-bit tables - these work fine for the
+    * 8-bit conversions but produce very slightly larger errors in the 16-bit
+    * log (about 1.2 as opposed to 0.7 absolute error in the final value).  To
+    * use these all the shifts below must be adjusted appropriately.
     */
    65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
    57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
@@ -1788,7 +1841,7 @@ png_8bit_l2[128] =
 #endif
 };
 
-static png_int_32
+PNG_STATIC png_int_32
 png_log8bit(unsigned int x)
 {
    unsigned int lg2 = 0;
@@ -1814,11 +1867,11 @@ png_log8bit(unsigned int x)
    return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
 }
 
-/* The above gives exact (to 16 binary places) log2 values for 8 bit images,
- * for 16 bit images we use the most significant 8 bits of the 16 bit value to
+/* The above gives exact (to 16 binary places) log2 values for 8-bit images,
+ * for 16-bit images we use the most significant 8 bits of the 16-bit value to
  * get an approximation then multiply the approximation by a correction factor
  * determined by the remaining up to 8 bits.  This requires an additional step
- * in the 16 bit case.
+ * in the 16-bit case.
  *
  * We want log2(value/65535), we have log2(v'/255), where:
  *
@@ -1827,8 +1880,8 @@ png_log8bit(unsigned int x)
  *
  * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
  * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
- * than 258.  The final factor also needs to correct for the fact that our 8 bit
- * value is scaled by 255, whereas the 16 bit values must be scaled by 65535.
+ * than 258.  The final factor also needs to correct for the fact that our 8-bit
+ * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
  *
  * This gives a final formula using a calculated value 'x' which is value/v' and
  * scaling by 65536 to match the above table:
@@ -1838,13 +1891,13 @@ png_log8bit(unsigned int x)
  * Since these numbers are so close to '1' we can use simple linear
  * interpolation between the two end values 256/257 (result -368.61) and 258/257
  * (result 367.179).  The values used below are scaled by a further 64 to give
- * 16 bit precision in the interpolation:
+ * 16-bit precision in the interpolation:
  *
  * Start (256): -23591
  * Zero  (257):      0
  * End   (258):  23499
  */
-static png_int_32
+PNG_STATIC png_int_32
 png_log16bit(png_uint_32 x)
 {
    unsigned int lg2 = 0;
@@ -1865,7 +1918,7 @@ png_log16bit(png_uint_32 x)
    if ((x & 0x8000) == 0)
       lg2 += 1, x <<= 1;
 
-   /* Calculate the base logarithm from the top 8 bits as a 28 bit fractional
+   /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
     * value.
     */
    lg2 <<= 28;
@@ -1895,18 +1948,18 @@ png_log16bit(png_uint_32 x)
    return (png_int_32)((lg2 + 2048) >> 12);
 }
 
-/* The 'exp()' case must invert the above, taking a 20 bit fixed point
- * logarithmic value and returning a 16 or 8 bit number as appropriate.  In
+/* The 'exp()' case must invert the above, taking a 20-bit fixed point
+ * logarithmic value and returning a 16 or 8-bit number as appropriate.  In
  * each case only the low 16 bits are relevant - the fraction - since the
  * integer bits (the top 4) simply determine a shift.
  *
- * The worst case is the 16 bit distinction between 65535 and 65534, this
+ * The worst case is the 16-bit distinction between 65535 and 65534, this
  * requires perhaps spurious accuracty in the decoding of the logarithm to
  * distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance
  * of getting this accuracy in practice.
  *
  * To deal with this the following exp() function works out the exponent of the
- * frational part of the logarithm by using an accurate 32 bit value from the
+ * frational part of the logarithm by using an accurate 32-bit value from the
  * top four fractional bits then multiplying in the remaining bits.
  */
 static png_uint_32
@@ -1915,7 +1968,7 @@ png_32bit_exp[16] =
 #  if PNG_DO_BC
       for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; }
 #  endif
-   /* NOTE: the first entry is deliberately set to the maximum 32 bit value. */
+   /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
    4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
    3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
    2553802834U, 2445529972U, 2341847524U, 2242560872U
@@ -1938,12 +1991,12 @@ for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
     0 45425.85339951654943850496
 #endif
 
-static png_uint_32
+PNG_STATIC png_uint_32
 png_exp(png_fixed_point x)
 {
    if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
    {
-      /* Obtain a 4 bit approximation */
+      /* Obtain a 4-bit approximation */
       png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
 
       /* Incorporate the low 12 bits - these decrease the returned value by
@@ -1986,13 +2039,13 @@ png_exp(png_fixed_point x)
    return 0;
 }
 
-static png_byte
+PNG_STATIC png_byte
 png_exp8bit(png_fixed_point lg2)
 {
-   /* Get a 32 bit value: */
+   /* Get a 32-bit value: */
    png_uint_32 x = png_exp(lg2);
 
-   /* Convert the 32 bit value to 0..255 by multiplying by 256-1, note that the
+   /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the
     * second, rounding, step can't overflow because of the first, subtraction,
     * step.
     */
@@ -2000,13 +2053,13 @@ png_exp8bit(png_fixed_point lg2)
    return (png_byte)((x + 0x7fffffU) >> 24);
 }
 
-static png_uint_16
+PNG_STATIC png_uint_16
 png_exp16bit(png_fixed_point lg2)
 {
-   /* Get a 32 bit value: */
+   /* Get a 32-bit value: */
    png_uint_32 x = png_exp(lg2);
 
-   /* Convert the 32 bit value to 0..65535 by multiplying by 65536-1: */
+   /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
    x -= x >> 16;
    return (png_uint_16)((x + 32767U) >> 16);
 }
@@ -2059,9 +2112,9 @@ png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
 }
 
 /* This does the right thing based on the bit_depth field of the
- * png_struct, interpreting values as 8 or 16 bit.  While the result
- * is nominally a 16 bit value if bit depth is 8 then the result is
- * 8 bit (as are the arguments.)
+ * png_struct, interpreting values as 8-bit or 16-bit.  While the result
+ * is nominally a 16-bit value if bit depth is 8 then the result is
+ * 8-bit (as are the arguments.)
  */
 png_uint_16 /* PRIVATE */
 png_gamma_correct(png_structp png_ptr, unsigned int value,
@@ -2084,7 +2137,7 @@ png_gamma_significant(png_fixed_point gamma_val)
        gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
 }
 
-/* Internal function to build a single 16 bit table - the table consists of
+/* Internal function to build a single 16-bit table - the table consists of
  * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
  * to shift the input values right (or 16-number_of_signifiant_bits).
  *
@@ -2111,7 +2164,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
           (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16));
 
       /* The 'threshold' test is repeated here because it can arise for one of
-       * the 16 bit tables even if the others don't hit it.
+       * the 16-bit tables even if the others don't hit it.
        */
       if (png_gamma_significant(gamma_val))
       {
@@ -2173,7 +2226,7 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
        (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
 
    /* 'num' is the number of tables and also the number of low bits of low
-    * bits of the input 16 bit value used to select a table.  Each table is
+    * bits of the input 16-bit value used to select a table.  Each table is
     * itself index by the high 8 bits of the value.
     */
    for (i = 0; i < num; i++)
@@ -2183,24 +2236,24 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
    /* 'gamma_val' is set to the reciprocal of the value calculated above, so
     * pow(out,g) is an *input* value.  'last' is the last input value set.
     *
-    * In the loop 'i' is used to find output values.  Since the output is 8
-    * bit there are only 256 possible values.  The tables are set up to
+    * In the loop 'i' is used to find output values.  Since the output is
+    * 8-bit there are only 256 possible values.  The tables are set up to
     * select the closest possible output value for each input by finding
     * the input value at the boundary between each pair of output values
     * and filling the table up to that boundary with the lower output
     * value.
     *
-    * The boundary values are 0.5,1.5..253.5,254.5.  Since these are 9 bit
-    * values the code below uses a 16 bit value in i; the values start at
+    * The boundary values are 0.5,1.5..253.5,254.5.  Since these are 9-bit
+    * values the code below uses a 16-bit value in i; the values start at
     * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
     * entries are filled with 255).  Start i at 128 and fill all 'last'
     * table entries <= 'max'
     */
    last = 0;
-   for (i = 0; i < 255; ++i) /* 8 bit output value */
+   for (i = 0; i < 255; ++i) /* 8-bit output value */
    {
       /* Find the corresponding maximum input value */
-      png_uint_16 out = (png_uint_16)(i * 257U); /* 16 bit output value */
+      png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */
 
       /* Find the boundary value in 16 bits: */
       png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
@@ -2223,7 +2276,7 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
    }
 }
 
-/* Build a single 8 bit table: same as the 16 bit case but much simpler (and
+/* Build a single 8-bit table: same as the 16-bit case but much simpler (and
  * typically much faster).  Note that libpng currently does no sBIT processing
  * (apparently contrary to the spec) so a 256 entry table is always generated.
  */
@@ -2258,8 +2311,9 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
          png_ptr->screen_gamma) : PNG_FP_1);
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
    defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-     if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
+     if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
      {
         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
             png_reciprocal(png_ptr->gamma));
@@ -2268,7 +2322,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
             png_ptr->screen_gamma > 0 ?  png_reciprocal(png_ptr->screen_gamma) :
             png_ptr->gamma/* Probably doing rgb_to_gray */);
      }
-#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
   }
   else
   {
@@ -2287,7 +2341,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
      else
         sig_bit = png_ptr->sig_bit.gray;
 
-     /* 16 bit gamma code uses this equation:
+     /* 16-bit gamma code uses this equation:
       *
       *   ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
       *
@@ -2302,7 +2356,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
       *
       * So the table 'n' corresponds to all those 'iv' of:
       *
-      *   <all high 8 bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
+      *   <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
       *
       */
      if (sig_bit > 0 && sig_bit < 16U)
@@ -2311,7 +2365,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
      else
         shift = 0; /* keep all 16 bits */
 
-     if (png_ptr->transformations & PNG_16_TO_8)
+     if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))
      {
         /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
          * the significant bits in the *input* when the output will
@@ -2327,7 +2381,12 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
      png_ptr->gamma_shift = shift;
 
 #ifdef PNG_16BIT_SUPPORTED
-     if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
+     /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now
+      * PNG_COMPOSE).  This effectively smashed the background calculation for
+      * 16-bit output because the 8-bit table assumes the result will be reduced
+      * to 8 bits.
+      */
+     if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8))
 #endif
          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma,
@@ -2341,8 +2400,9 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
 #endif
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
    defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
-     if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
+     if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY))
      {
         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
             png_reciprocal(png_ptr->gamma));
@@ -2355,7 +2415,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
             png_ptr->gamma/* Probably doing rgb_to_gray */);
      }
-#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
   }
 }
 #endif /* READ_GAMMA */
index 0af42b170ecd9fb2b5acb4be956aa64496830167..c655a51af262f7783b4dc868267e5138d64a7c71 100644 (file)
@@ -1,7 +1,7 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.5.2 - March 31, 2011
+ * libpng version 1.5.4 - July 7, 2011
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -11,7 +11,7 @@
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.5.2 - March 31, 2011: Glenn
+ *   libpng versions 0.97, January 1998, through 1.5.4 - July 7, 2011: Glenn
  *   See also "Contributing Authors", below.
  *
  * Note about libpng version numbers:
  *    1.5.2beta01-03          15    10502  15.so.15.2[.0]
  *    1.5.2rc01-03            15    10502  15.so.15.2[.0]
  *    1.5.2                   15    10502  15.so.15.2[.0]
+ *    1.5.3beta01-10          15    10503  15.so.15.3[.0]
+ *    1.5.3rc01-02            15    10503  15.so.15.3[.0]
+ *    1.5.3beta11             15    10503  15.so.15.3[.0]
+ *    1.5.3 [omitted]
+ *    1.5.4beta01-08          15    10504  15.so.15.4[.0]
+ *    1.5.4rc01               15    10504  15.so.15.4[.0]
+ *    1.5.4                   15    10504  15.so.15.4[.0]
  *
  *   Henceforth the source version will match the shared-library major
  *   and minor numbers; the shared-library major version number will be
  *
  * This code is released under the libpng license.
  *
- * libpng versions 1.2.6, August 15, 2004, through 1.5.2, March 31, 2011, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are
  * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
  * distributed according to the same disclaimer and license as libpng-1.2.5
  * with the following individual added to the list of Contributing Authors:
  * Y2K compliance in libpng:
  * =========================
  *
- *    March 31, 2011
+ *    July 7, 2011
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.5.2 are Y2K compliant.  It is my belief that
+ *    upward through 1.5.4 are Y2K compliant.  It is my belief that
  *    earlier versions were also Y2K compliant.
  *
- *    Libpng only has three year fields.  One is a 2-byte unsigned integer
- *    that will hold years up to 65535.  The other two hold the date in text
+ *    Libpng only has two year fields.  One is a 2-byte unsigned integer
+ *    that will hold years up to 65535.  The other holds the date in text
  *    format, and will hold years up to 9999.
  *
  *    The integer is
  *        "png_uint_16 year" in png_time_struct.
  *
- *    The strings are
- *        "png_charp time_buffer" in png_struct and
- *        "near_time_buffer", which is a local character string in png.c.
+ *    The string is
+ *        "png_char time_buffer" in png_struct
  *
  *    There are seven time-related functions:
  *        png.c: png_convert_to_rfc_1123() in png.c
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.5.2"
+#define PNG_LIBPNG_VER_STRING "1.5.4"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.5.2 - March 31, 2011\n"
+     " libpng version 1.5.4 - July 7, 2011\n"
 
 #define PNG_LIBPNG_VER_SONUM   15
 #define PNG_LIBPNG_VER_DLLNUM  15
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   5
-#define PNG_LIBPNG_VER_RELEASE 2
+#define PNG_LIBPNG_VER_RELEASE 4
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
  */
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10502 /* 1.5.2 */
+#define PNG_LIBPNG_VER 10504 /* 1.5.4 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -517,7 +523,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_5_2;
+typedef char* png_libpng_version_1_5_4;
 
 /* Three color definitions.  The order of the red, green, and blue, (and the
  * exact size) is not important, although the size of the fields need to
@@ -594,7 +600,7 @@ typedef png_sPLT_t FAR * FAR * png_sPLT_tpp;
  * and whether that contents is compressed or not.  The "key" field
  * points to a regular zero-terminated C string.  The "text", "lang", and
  * "lang_key" fields can be regular C strings, empty strings, or NULL pointers.
- * However, the structure returned by png_get_text() will always contain
+ * However, the structure returned by png_get_text() will always contain
  * regular zero-terminated C strings (possibly empty), never NULL pointers,
  * so they can be safely used in printf() and other string-handling functions.
  */
@@ -665,12 +671,24 @@ typedef struct png_unknown_chunk_t
     /* libpng-using applications should NOT directly modify this byte. */
     png_byte location; /* mode of operation at read time */
 }
+
+
 png_unknown_chunk;
 typedef png_unknown_chunk FAR * png_unknown_chunkp;
 typedef PNG_CONST png_unknown_chunk FAR * png_const_unknown_chunkp;
 typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp;
 #endif
 
+/* Values for the unknown chunk location byte */
+
+#define PNG_HAVE_IHDR  0x01
+#define PNG_HAVE_PLTE  0x02
+#define PNG_AFTER_IDAT 0x08
+
+/* The complete definition of png_info has, as of libpng-1.5.0,
+ * been moved into a separate header file that is not accessible to
+ * applications.  Read libpng-manual.txt or libpng.3 for more info.
+ */
 typedef struct png_info_def png_info;
 typedef png_info FAR * png_infop;
 typedef PNG_CONST png_info FAR * png_const_infop;
@@ -686,6 +704,8 @@ typedef png_info FAR * FAR * png_infopp;
  */
 #define PNG_FP_1    100000
 #define PNG_FP_HALF  50000
+#define PNG_FP_MAX  ((png_fixed_point)0x7fffffffL)
+#define PNG_FP_MIN  (-PNG_FP_MAX)
 
 /* These describe the color_type field in png_info. */
 /* color type masks */
@@ -792,6 +812,14 @@ typedef struct png_row_info_struct
 typedef png_row_info FAR * png_row_infop;
 typedef png_row_info FAR * FAR * png_row_infopp;
 
+/* The complete definition of png_struct has, as of libpng-1.5.0,
+ * been moved into a separate header file that is not accessible to
+ * applications.  Read libpng-manual.txt or libpng.3 for more info.
+ */
+typedef struct png_struct_def png_struct;
+typedef PNG_CONST png_struct FAR * png_const_structp;
+typedef png_struct FAR * png_structp;
+
 /* These are the function types for the I/O functions and for the functions
  * that allow the user to override the default I/O functions with his or her
  * own.  The png_error_ptr type should match that of user-supplied warning
@@ -800,10 +828,6 @@ typedef png_row_info FAR * FAR * png_row_infopp;
  * modify the buffer it is passed. The 'read' function, on the other hand, is
  * expected to return the read data in the buffer.
  */
-typedef struct png_struct_def png_struct;
-typedef PNG_CONST png_struct FAR * png_const_structp;
-typedef png_struct FAR * png_structp;
-
 typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp));
 typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t));
 typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp));
@@ -845,25 +869,18 @@ typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp));
 #endif
 
 #ifdef PNG_SETJMP_SUPPORTED
-/* This must match the function definition in <setjmp.h>, and the
- * application must include this before png.h to obtain the definition
- * of jmp_buf.  The function is required to be PNG_NORETURN.  (Note that
- * PNG_PTR_NORETURN is used here because current versions of the Microsoft
- * C compiler do not support the PNG_NORETURN attribute on a pointer.)
- *
- * If you get a type warning from the compiler when linking against this line
- * then your compiler has 'longjmp' that does not match the requirements of the
- * compiler that built libpng.  You will have to write a wrapper function for
- * your compiler's longjmp and call png_set_longjmp_fn directly (not via the
- * png_jmpbuf macro.)
- *
- * If you get a warning here while building the library you will need to make
+/* This must match the function definition in <setjmp.h>, and the application
+ * must include this before png.h to obtain the definition of jmp_buf.  The
+ * function is required to be PNG_NORETURN, but this is not checked.  If the
+ * function does return the application will crash via an abort() or similar
+ * system level call.
+ *
+ * If you get a warning here while building the library you may need to make
  * changes to ensure that pnglibconf.h records the calling convention used by
  * your compiler.  This may be very difficult - try using a different compiler
  * to build the library!
  */
-typedef PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)),
-   PNG_PTR_NORETURN);
+PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
 #endif
 
 /* Transform masks for the high-level interface */
@@ -885,6 +902,9 @@ typedef PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)),
 #define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */
 /* Added to libpng-1.4.0 */
 #define PNG_TRANSFORM_GRAY_TO_RGB   0x2000      /* read only */
+/* Added to libpng-1.5.4 */
+#define PNG_TRANSFORM_EXPAND_16     0x4000      /* read only */
+#define PNG_TRANSFORM_SCALE_16      0x8000      /* read only */
 
 /* Flags for MNG supported features */
 #define PNG_FLAG_MNG_EMPTY_PLTE     0x01
@@ -1079,7 +1099,7 @@ PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structp png_ptr));
 #endif
 
 #ifdef PNG_READ_EXPAND_16_SUPPORTED
-/* Expand to 16 bit channels, forces conversion of palette to RGB and expansion
+/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion
  * of a tRNS chunk if present.
  */
 PNG_EXPORT(221, void, png_set_expand_16, (png_structp png_ptr));
@@ -1106,8 +1126,219 @@ PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp
     png_ptr));
 #endif
 
+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
 PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
     png_colorp palette));
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+/* How the alpha channel is interpreted - this affects how the color channels of
+ * a PNG file are returned when an alpha channel, or tRNS chunk in a palette
+ * file, is present.
+ *
+ * This has no effect on the way pixels are written into a PNG output
+ * datastream. The color samples in a PNG datastream are never premultiplied
+ * with the alpha samples.
+ *
+ * The default is to return data according to the PNG specification: the alpha
+ * channel is a linear measure of the contribution of the pixel to the
+ * corresponding composited pixel.  The gamma encoded color channels must be
+ * scaled according to the contribution and to do this it is necessary to undo
+ * the encoding, scale the color values, perform the composition and reencode
+ * the values.  This is the 'PNG' mode.
+ *
+ * The alternative is to 'associate' the alpha with the color information by
+ * storing color channel values that have been scaled by the alpha.  The
+ * advantage is that the color channels can be resampled (the image can be
+ * scaled) in this form.  The disadvantage is that normal practice is to store
+ * linear, not (gamma) encoded, values and this requires 16-bit channels for
+ * still images rather than the 8-bit channels that are just about sufficient if
+ * gamma encoding is used.  In addition all non-transparent pixel values,
+ * including completely opaque ones, must be gamma encoded to produce the final
+ * image.  This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the
+ * latter being the two common names for associated alpha color channels.)
+ *
+ * Since it is not necessary to perform arithmetic on opaque color values so
+ * long as they are not to be resampled and are in the final color space it is
+ * possible to optimize the handling of alpha by storing the opaque pixels in
+ * the PNG format (adjusted for the output color space) while storing partially
+ * opaque pixels in the standard, linear, format.  The accuracy required for
+ * standard alpha composition is relatively low, because the pixels are
+ * isolated, therefore typically the accuracy loss in storing 8-bit linear
+ * values is acceptable.  (This is not true if the alpha channel is used to
+ * simulate transparency over large areas - use 16 bits or the PNG mode in
+ * this case!)  This is the 'OPTIMIZED' mode.  For this mode a pixel is
+ * treated as opaque only if the alpha value is equal to the maximum value.
+ *
+ * The final choice is to gamma encode the alpha channel as well.  This is
+ * broken because, in practice, no implementation that uses this choice
+ * correctly undoes the encoding before handling alpha composition.  Use this
+ * choice only if other serious errors in the software or hardware you use
+ * mandate it; the typical serious error is for dark halos to appear around
+ * opaque areas of the composited PNG image because of arithmetic overflow.
+ *
+ * The API function png_set_alpha_mode specifies which of these choices to use
+ * with an enumerated 'mode' value and the gamma of the required output:
+ */
+#define PNG_ALPHA_PNG           0 /* according to the PNG standard */
+#define PNG_ALPHA_STANDARD      1 /* according to Porter/Duff */
+#define PNG_ALPHA_ASSOCIATED    1 /* as above; this is the normal practice */
+#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */
+#define PNG_ALPHA_OPTIMIZED     2 /* 'PNG' for opaque pixels, else 'STANDARD' */
+#define PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */
+
+PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode,
+    double output_gamma));
+PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr,
+    int mode, png_fixed_point output_gamma));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+/* The output_gamma value is a screen gamma in libpng terminology: it expresses
+ * how to decode the output values, not how they are encoded.  The values used
+ * correspond to the normal numbers used to describe the overall gamma of a
+ * computer display system; for example 2.2 for an sRGB conformant system.  The
+ * values are scaled by 100000 in the _fixed version of the API (so 220000 for
+ * sRGB.)
+ *
+ * The inverse of the value is always used to provide a default for the PNG file
+ * encoding if it has no gAMA chunk and if png_set_gamma() has not been called
+ * to override the PNG gamma information.
+ *
+ * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode
+ * opaque pixels however pixels with lower alpha values are not encoded,
+ * regardless of the output gamma setting.
+ *
+ * When the standard Porter Duff handling is requested with mode 1 the output
+ * encoding is set to be linear and the output_gamma value is only relevant
+ * as a default for input data that has no gamma information.  The linear output
+ * encoding will be overridden if png_set_gamma() is called - the results may be
+ * highly unexpected!
+ *
+ * The following numbers are derived from the sRGB standard and the research
+ * behind it.  sRGB is defined to be approximated by a PNG gAMA chunk value of
+ * 0.45455 (1/2.2) for PNG.  The value implicitly includes any viewing
+ * correction required to take account of any differences in the color
+ * environment of the original scene and the intended display environment; the
+ * value expresses how to *decode* the image for display, not how the original
+ * data was *encoded*.
+ *
+ * sRGB provides a peg for the PNG standard by defining a viewing environment.
+ * sRGB itself, and earlier TV standards, actually use a more complex transform
+ * (a linear portion then a gamma 2.4 power law) than PNG can express.  (PNG is
+ * limited to simple power laws.)  By saying that an image for direct display on
+ * an sRGB conformant system should be stored with a gAMA chunk value of 45455
+ * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification
+ * makes it possible to derive values for other display systems and
+ * environments.
+ *
+ * The Mac value is deduced from the sRGB based on an assumption that the actual
+ * extra viewing correction used in early Mac display systems was implemented as
+ * a power 1.45 lookup table.
+ *
+ * Any system where a programmable lookup table is used or where the behavior of
+ * the final display device characteristics can be changed requires system
+ * specific code to obtain the current characteristic.  However this can be
+ * difficult and most PNG gamma correction only requires an approximate value.
+ *
+ * By default, if png_set_alpha_mode() is not called, libpng assumes that all
+ * values are unencoded, linear, values and that the output device also has a
+ * linear characteristic.  This is only very rarely correct - it is invariably
+ * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the
+ * default if you don't know what the right answer is!
+ *
+ * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS
+ * 10.6) which used a correction table to implement a somewhat lower gamma on an
+ * otherwise sRGB system.
+ *
+ * Both these values are reserved (not simple gamma values) in order to allow
+ * more precise correction internally in the future.
+ *
+ * NOTE: the following values can be passed to either the fixed or floating
+ * point APIs, but the floating point API will also accept floating point
+ * values.
+ */
+#define PNG_DEFAULT_sRGB -1       /* sRGB gamma and color space */
+#define PNG_GAMMA_MAC_18 -2       /* Old Mac '1.8' gamma and color space */
+#define PNG_GAMMA_sRGB   220000   /* Television standards--matches sRGB gamma */
+#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */
+#endif
+
+/* The following are examples of calls to png_set_alpha_mode to achieve the
+ * required overall gamma correction and, where necessary, alpha
+ * premultiplication.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ *    This is the default libpng handling of the alpha channel - it is not
+ *    pre-multiplied into the color components.  In addition the call states
+ *    that the output is for a sRGB system and causes all PNG files without gAMA
+ *    chunks to be assumed to be encoded using sRGB.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ *    In this case the output is assumed to be something like an sRGB conformant
+ *    display preceeded by a power-law lookup table of power 1.45.  This is how
+ *    early Mac systems behaved.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);
+ *    This is the classic Jim Blinn approach and will work in academic
+ *    environments where everything is done by the book.  It has the shortcoming
+ *    of assuming that input PNG data with no gamma information is linear - this
+ *    is unlikely to be correct unless the PNG files where generated locally.
+ *    Most of the time the output precision will be so low as to show
+ *    significant banding in dark areas of the image.
+ *
+ * png_set_expand_16(pp);
+ * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);
+ *    This is a somewhat more realistic Jim Blinn inspired approach.  PNG files
+ *    are assumed to have the sRGB encoding if not marked with a gamma value and
+ *    the output is always 16 bits per component.  This permits accurate scaling
+ *    and processing of the data.  If you know that your input PNG files were
+ *    generated locally you might need to replace PNG_DEFAULT_sRGB with the
+ *    correct value for your system.
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);
+ *    If you just need to composite the PNG image onto an existing background
+ *    and if you control the code that does this you can use the optimization
+ *    setting.  In this case you just copy completely opaque pixels to the
+ *    output.  For pixels that are not completely transparent (you just skip
+ *    those) you do the composition math using png_composite or png_composite_16
+ *    below then encode the resultant 8-bit or 16-bit values to match the output
+ *    encoding.
+ *
+ * Other cases
+ *    If neither the PNG nor the standard linear encoding work for you because
+ *    of the software or hardware you use then you have a big problem.  The PNG
+ *    case will probably result in halos around the image.  The linear encoding
+ *    will probably result in a washed out, too bright, image (it's actually too
+ *    contrasty.)  Try the ALPHA_OPTIMIZED mode above - this will probably
+ *    substantially reduce the halos.  Alternatively try:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);
+ *    This option will also reduce the halos, but there will be slight dark
+ *    halos round the opaque parts of the image where the background is light.
+ *    In the OPTIMIZED mode the halos will be light halos where the background
+ *    is dark.  Take your pick - the halos are unavoidable unless you can get
+ *    your hardware/software fixed!  (The OPTIMIZED approach is slightly
+ *    faster.)
+ *
+ * When the default gamma of PNG files doesn't match the output gamma.
+ *    If you have PNG files with no gamma information png_set_alpha_mode allows
+ *    you to provide a default gamma, but it also sets the ouput gamma to the
+ *    matching value.  If you know your PNG files have a gamma that doesn't
+ *    match the output you can take advantage of the fact that
+ *    png_set_alpha_mode always sets the output gamma but only sets the PNG
+ *    default if it is not already set:
+ *
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
+ * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
+ *    The first call sets both the default and the output gamma values, the
+ *    second call overrides the output gamma without changing the default.  This
+ *    is easier than achieving the same effect with png_set_gamma.  You must use
+ *    PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will
+ *    fire if more than one call to png_set_alpha_mode and png_set_background is
+ *    made in the same read operation, however multiple calls with PNG_ALPHA_PNG
+ *    are ignored.
+ */
 
 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 PNG_EXPORT(36, void, png_set_strip_alpha, (png_structp png_ptr));
@@ -1175,7 +1406,11 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr));
 #endif
 
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
-/* Handle alpha and tRNS by replacing with a background color. */
+/* Handle alpha and tRNS by replacing with a background color.  Prior to
+ * libpng-1.5.4 this API must not be called before the PNG file header has been
+ * read.  Doing so will result in unexpected behavior and possible warnings or
+ * errors if the PNG file contains a bKGD chunk.
+ */
 PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr,
     png_const_color_16p background_color, int background_gamma_code,
     int need_expand, double background_gamma));
@@ -1190,7 +1425,13 @@ PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr,
 #  define PNG_BACKGROUND_GAMMA_UNIQUE  3
 #endif
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+/* Scale a 16-bit depth file down to 8-bit, accurately. */
+PNG_EXPORT(229, void, png_set_scale_16, (png_structp png_ptr));
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */
 /* Strip the second byte of information from a 16-bit depth file. */
 PNG_EXPORT(48, void, png_set_strip_16, (png_structp png_ptr));
 #endif
@@ -1211,12 +1452,22 @@ PNG_EXPORT(49, void, png_set_quantize,
  */
 #define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001)
 
-/* Handle gamma correction. Screen_gamma=(display_exponent) */
+/* Handle gamma correction. Screen_gamma=(display_exponent).
+ * NOTE: this API simply sets the screen and file gamma values. It will
+ * therefore override the value for gamma in a PNG file if it is called after
+ * the file header has been read - use with care  - call before reading the PNG
+ * file for best results!
+ *
+ * These routines accept the same gamma values as png_set_alpha_mode (described
+ * above).  The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either
+ * API (floating point or fixed.)  Notice, however, that the 'file_gamma' value
+ * is the inverse of a 'screen gamma' value.
+ */
 PNG_FP_EXPORT(50, void, png_set_gamma,
     (png_structp png_ptr, double screen_gamma,
-    double default_file_gamma));
+    double override_file_gamma));
 PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr,
-    png_fixed_point screen_gamma, png_fixed_point default_file_gamma));
+    png_fixed_point screen_gamma, png_fixed_point override_file_gamma));
 #endif
 
 #ifdef PNG_WRITE_FLUSH_SUPPORTED
@@ -1391,6 +1642,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
 #define PNG_FILTER_HEURISTIC_WEIGHTED   2  /* Experimental feature */
 #define PNG_FILTER_HEURISTIC_LAST       3  /* Not a valid value */
 
+#ifdef PNG_WRITE_SUPPORTED
 /* Set the library compression level.  Currently, valid values range from
  * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
  * (0 - no compression, 9 - "maximal" compression).  Note that tests have
@@ -1407,11 +1659,36 @@ PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structp png_ptr,
 PNG_EXPORT(71, void, png_set_compression_strategy, (png_structp png_ptr,
     int strategy));
 
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
 PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr,
     int window_bits));
 
 PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr,
     int method));
+#endif
+
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+/* Also set zlib parameters for compressing non-IDAT chunks */
+PNG_EXPORT(222, void, png_set_text_compression_level,
+    (png_structp png_ptr, int level));
+
+PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structp png_ptr,
+    int mem_level));
+
+PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structp png_ptr,
+    int strategy));
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp
+    png_ptr, int window_bits));
+
+PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr,
+    int method));
+#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
 
 /* These next functions are called for input/output, memory, and error
  * handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,
@@ -1623,6 +1900,7 @@ PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr,
 PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN);
 #endif
 
+#ifdef PNG_WARNINGS_SUPPORTED
 /* Non-fatal error in libpng.  Can continue, but may have a problem. */
 PNG_EXPORT(105, void, png_warning, (png_structp png_ptr,
     png_const_charp warning_message));
@@ -1630,6 +1908,7 @@ PNG_EXPORT(105, void, png_warning, (png_structp png_ptr,
 /* Non-fatal error in libpng, chunk name is prepended to message. */
 PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr,
     png_const_charp warning_message));
+#endif
 
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 /* Benign error in libpng.  Can continue, but may have a problem.
@@ -2297,7 +2576,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
  * scripts/symbols.def as well.
  */
 #ifdef PNG_EXPORT_LAST_ORDINAL
-  PNG_EXPORT_LAST_ORDINAL(221);
+  PNG_EXPORT_LAST_ORDINAL(229);
 #endif
 
 #ifdef __cplusplus
index c82fa5866c1e5119235121304f36ee21a649ac0b..222816e37213075d291fbe0743b0f00f6467fad8 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.5.2 - March 31, 2011
+ * libpng version 1.5.4 - July 7, 2011
  *
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 #    ifndef PNG_NORETURN
 #      define PNG_NORETURN   __attribute__((__noreturn__))
 #    endif
-#    ifndef PNG_PTR_NORETURN
-       /* It's not enough to have the compiler be the correct compiler at
-        * this point - it's necessary for the library (which defines
-        * the type of the library longjmp) to also be the GNU library.
-        * This is because many systems use the GNU compiler with a
-        * non-GNU libc implementation.  Min/GW headers are also compatible
-        * with GCC as well as uclibc, so it seems best to exclude known
-        * problem libcs here rather than just including known libcs.
-        *
-        * NOTE: this relies on the only use of PNG_PTR_NORETURN being with
-        * the system longjmp.  If the same type is used elsewhere then this
-        * will need to be changed.
-        */
-#      if !defined(__CYGWIN__)
-#         define PNG_PTR_NORETURN   __attribute__((__noreturn__))
-#      endif
-#    endif
 #    ifndef PNG_ALLOCATED
 #      define PNG_ALLOCATED  __attribute__((__malloc__))
 #    endif
 #      ifndef PNG_DEPRECATED
 #        define PNG_DEPRECATED __attribute__((__deprecated__))
 #      endif
-#      ifndef PNG_DEPSTRUCT
-#        define PNG_DEPSTRUCT  __attribute__((__deprecated__))
-#      endif
 #      ifndef PNG_PRIVATE
 #        if 0 /* Doesn't work so we use deprecated instead*/
 #          define PNG_PRIVATE \
 #    ifndef PNG_NORETURN
 #      define PNG_NORETURN   __declspec(noreturn)
 #    endif
-#    ifndef PNG_PTR_NORETURN
-#      define PNG_PTR_NORETURN /* not supported */
-#    endif
 #    ifndef PNG_ALLOCATED
-#      define PNG_ALLOCATED __declspec(restrict)
+#      if (_MSC_VER >= 1400)
+#        define PNG_ALLOCATED __declspec(restrict)
+#      endif
 #    endif
 
     /* This specifically protects structure members that should only be
 #      ifndef PNG_DEPRECATED
 #        define PNG_DEPRECATED __declspec(deprecated)
 #      endif
-#      ifndef PNG_DEPSTRUCT
-#        define PNG_DEPSTRUCT  __declspec(deprecated)
-#      endif
 #      ifndef PNG_PRIVATE
 #        define PNG_PRIVATE __declspec(deprecated)
 #      endif
 #ifndef PNG_NORETURN
 #  define PNG_NORETURN    /* This function does not return */
 #endif
-#ifndef PNG_PTR_NORETURN
-#  define PNG_PTR_NORETURN /* This function does not return */
-#endif
 #ifndef PNG_ALLOCATED
 #  define PNG_ALLOCATED   /* The result of the function is new memory */
 #endif
-#ifndef PNG_DEPSTRUCT
-#  define PNG_DEPSTRUCT   /* Access to this struct member is deprecated */
-#endif
 #ifndef PNG_PRIVATE
 #  define PNG_PRIVATE     /* This is a private libpng function */
 #endif
index 8290bb4106efbd5f18563a7c69f82e73bf47982c..4d4cebafa94bc80ef35d5c11bf616977ad73a553 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
  *
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -89,15 +89,121 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN)
 PNG_FUNCTION(void,PNGAPI
 png_err,(png_structp png_ptr),PNG_NORETURN)
 {
+   /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
+    * erroneously as '\0', instead of the empty string "".  This was
+    * apparently an error, introduced in libpng-1.2.20, and png_default_error
+    * will crash in this case.
+    */
    if (png_ptr != NULL && png_ptr->error_fn != NULL)
-      (*(png_ptr->error_fn))(png_ptr, '\0');
+      (*(png_ptr->error_fn))(png_ptr, "");
 
    /* If the custom handler doesn't exist, or if it returns,
       use the default handler, which will not return. */
-   png_default_error(png_ptr, '\0');
+   png_default_error(png_ptr, "");
 }
 #endif /* PNG_ERROR_TEXT_SUPPORTED */
 
+/* Utility to safely appends strings to a buffer.  This never errors out so
+ * error checking is not required in the caller.
+ */
+size_t
+png_safecat(png_charp buffer, size_t bufsize, size_t pos,
+   png_const_charp string)
+{
+   if (buffer != NULL && pos < bufsize)
+   {
+      if (string != NULL)
+         while (*string != '\0' && pos < bufsize-1)
+           buffer[pos++] = *string++;
+
+      buffer[pos] = '\0';
+   }
+
+   return pos;
+}
+
+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Utility to dump an unsigned value into a buffer, given a start pointer and
+ * and end pointer (which should point just *beyond* the end of the buffer!)
+ * Returns the pointer to the start of the formatted string.
+ */
+png_charp
+png_format_number(png_const_charp start, png_charp end, int format,
+   png_alloc_size_t number)
+{
+   int count = 0;    /* number of digits output */
+   int mincount = 1; /* minimum number required */
+   int output = 0;   /* digit output (for the fixed point format) */
+
+   *--end = '\0';
+
+   /* This is written so that the loop always runs at least once, even with
+    * number zero.
+    */
+   while (end > start && (number != 0 || count < mincount))
+   {
+
+      static const char digits[] = "0123456789ABCDEF";
+
+      switch (format)
+      {
+         case PNG_NUMBER_FORMAT_fixed:
+            /* Needs five digits (the fraction) */
+            mincount = 5;
+            if (output || number % 10 != 0)
+            {
+               *--end = digits[number % 10];
+               output = 1;
+            }
+            number /= 10;
+            break;
+
+         case PNG_NUMBER_FORMAT_02u:
+            /* Expects at least 2 digits. */
+            mincount = 2;
+            /* fall through */
+
+         case PNG_NUMBER_FORMAT_u:
+            *--end = digits[number % 10];
+            number /= 10;
+            break;
+
+         case PNG_NUMBER_FORMAT_02x:
+            /* This format expects at least two digits */
+            mincount = 2;
+            /* fall through */
+
+         case PNG_NUMBER_FORMAT_x:
+            *--end = digits[number & 0xf];
+            number >>= 4;
+            break;
+
+         default: /* an error */
+            number = 0;
+            break;
+      }
+
+      /* Keep track of the number of digits added */
+      ++count;
+
+      /* Float a fixed number here: */
+      if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start)
+      {
+         /* End of the fraction, but maybe nothing was output?  In that case
+          * drop the decimal point.  If the number is a true zero handle that
+          * here.
+          */
+         if (output)
+            *--end = '.';
+         else if (number == 0) /* and !output */
+            *--end = '0';
+      }
+   }
+
+   return end;
+}
+#endif
+
 #ifdef PNG_WARNINGS_SUPPORTED
 /* This function is called whenever there is a non-fatal error.  This function
  * should not be changed.  If there is a need to handle warnings differently,
@@ -128,6 +234,115 @@ png_warning(png_structp png_ptr, png_const_charp warning_message)
    else
       png_default_warning(png_ptr, warning_message + offset);
 }
+
+/* These functions support 'formatted' warning messages with up to
+ * PNG_WARNING_PARAMETER_COUNT parameters.  In the format string the parameter
+ * is introduced by @<number>, where 'number' starts at 1.  This follows the
+ * standard established by X/Open for internationalizable error messages.
+ */
+void
+png_warning_parameter(png_warning_parameters p, int number,
+   png_const_charp string)
+{
+   if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)
+      (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);
+}
+
+void
+png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
+   png_alloc_size_t value)
+{
+   char buffer[PNG_NUMBER_BUFFER_SIZE];
+   png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
+}
+
+void
+png_warning_parameter_signed(png_warning_parameters p, int number, int format,
+   png_int_32 value)
+{
+   png_alloc_size_t u;
+   png_charp str;
+   char buffer[PNG_NUMBER_BUFFER_SIZE];
+
+   /* Avoid overflow by doing the negate in a png_alloc_size_t: */
+   u = (png_alloc_size_t)value;
+   if (value < 0)
+      u = ~u + 1;
+
+   str = PNG_FORMAT_NUMBER(buffer, format, u);
+
+   if (value < 0 && str > buffer)
+      *--str = '-';
+
+   png_warning_parameter(p, number, str);
+}
+
+void
+png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
+   png_const_charp message)
+{
+   /* The internal buffer is just 128 bytes - enough for all our messages,
+    * overflow doesn't happen because this code checks!
+    */
+   size_t i;
+   char msg[128];
+
+   for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i)
+   {
+      if (*message == '@')
+      {
+         int parameter = -1;
+         switch (*++message)
+         {
+            case '1':
+               parameter = 0;
+               break;
+
+            case '2':
+               parameter = 1;
+               break;
+
+            case '\0':
+               continue; /* To break out of the for loop above. */
+
+            default:
+               break;
+         }
+
+         if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT)
+         {
+            /* Append this parameter */
+            png_const_charp parm = p[parameter];
+            png_const_charp pend = p[parameter] + (sizeof p[parameter]);
+
+            /* No need to copy the trailing '\0' here, but there is no guarantee
+             * that parm[] has been initialized, so there is no guarantee of a
+             * trailing '\0':
+             */
+            for (; i<(sizeof msg)-1 && parm != '\0' && parm < pend; ++i)
+               msg[i] = *parm++;
+
+            ++message;
+            continue;
+         }
+
+         /* else not a parameter and there is a character after the @ sign; just
+          * copy that.
+          */
+      }
+
+      /* At this point *message can't be '\0', even in the bad parameter case
+       * above where there is a lone '@' at the end of the message string.
+       */
+      msg[i] = *message++;
+   }
+
+   /* i is always less than (sizeof msg), so: */
+   msg[i] = '\0';
+
+   /* And this is the formatted message: */
+   png_warning(png_ptr, msg);
+}
 #endif /* PNG_WARNINGS_SUPPORTED */
 
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
@@ -185,8 +400,13 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
    {
       buffer[iout++] = ':';
       buffer[iout++] = ' ';
-      png_memcpy(buffer + iout, error_message, PNG_MAX_ERROR_TEXT);
-      buffer[iout + PNG_MAX_ERROR_TEXT - 1] = '\0';
+
+      iin = 0;
+      while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')
+         buffer[iout++] = error_message[iin++];
+
+      /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */
+      buffer[iout] = '\0';
    }
 }
 #endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */
@@ -272,7 +492,7 @@ png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn,
       return NULL;
 
    png_ptr->longjmp_fn = longjmp_fn;
-   return &png_ptr->png_jmpbuf;
+   return &png_ptr->longjmp_buffer;
 }
 #endif
 
@@ -287,7 +507,8 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message),
 {
 #ifdef PNG_CONSOLE_IO_SUPPORTED
 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
-   if (*error_message == PNG_LITERAL_SHARP)
+   /* Check on NULL only added in 1.5.4 */
+   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
    {
       /* Strip "#nnnn " from beginning of error message. */
       int offset;
@@ -317,11 +538,11 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message),
    else
 #endif
    {
-      fprintf(stderr, "libpng error: %s", error_message);
+      fprintf(stderr, "libpng error: %s", error_message ? error_message :
+         "undefined");
       fprintf(stderr, PNG_STRING_NEWLINE);
    }
-#endif
-#ifndef PNG_CONSOLE_IO_SUPPORTED
+#else
    PNG_UNUSED(error_message) /* Make compiler happy */
 #endif
    png_longjmp(png_ptr, 1);
@@ -335,13 +556,13 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN)
    {
 #  ifdef USE_FAR_KEYWORD
       {
-         jmp_buf png_jmpbuf;
-         png_memcpy(png_jmpbuf, png_ptr->png_jmpbuf, png_sizeof(jmp_buf));
-         png_ptr->longjmp_fn(png_jmpbuf, val);
+         jmp_buf tmp_jmpbuf;
+         png_memcpy(tmp_jmpbuf, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
+         png_ptr->longjmp_fn(tmp_jmpbuf, val);
       }
 
 #  else
-   png_ptr->longjmp_fn(png_ptr->png_jmpbuf, val);
+   png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val);
 #  endif
    }
 #endif
@@ -403,7 +624,7 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message)
 /* This function is called when the application wants to use another method
  * of handling errors and warnings.  Note that the error function MUST NOT
  * return to the calling routine or serious problems will occur.  The return
- * method used in the default routine calls longjmp(png_ptr->png_jmpbuf, 1)
+ * method used in the default routine calls longjmp(png_ptr->longjmp_buffer, 1)
  */
 void PNGAPI
 png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
@@ -414,7 +635,11 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
 
    png_ptr->error_ptr = error_ptr;
    png_ptr->error_fn = error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    png_ptr->warning_fn = warning_fn;
+#else
+   PNG_UNUSED(warning_fn)
+#endif
 }
 
 
index fa19f85e72c00895f5de3be5557e25cfb79b680d..a33bfab06de28fc52096ddb90b8bca6915abc8c1 100644 (file)
@@ -138,7 +138,6 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
     * single color specified that should be treated as fully transparent.
     * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
     */
-   png_bytep trans;    /* alpha values for paletted image */
    png_bytep trans_alpha;    /* alpha values for paletted image */
    png_color_16 trans_color; /* transparent color for non-palette image */
 #endif
index a15d8b085936b5eb3271eaf3d4602198b12bad03..ea606d6a624a98c243ef6ace09cc059e56157e03 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngmem.c - stub functions for memory allocation
  *
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -187,8 +187,9 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
             int num_blocks;
             png_uint_32 total_size;
             png_bytep table;
-            int i;
+            int i, mem_level, window_bits;
             png_byte huge * hptr;
+            int window_bits
 
             if (ret != NULL)
             {
@@ -196,14 +197,22 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
                ret = NULL;
             }
 
-            if (png_ptr->zlib_window_bits > 14)
-               num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
+            window_bits =
+                png_ptr->zlib_window_bits >= png_ptr->zlib_text_window_bits ?
+                png_ptr->zlib_window_bits : png_ptr->zlib_text_window_bits;
+
+            if (window_bits > 14)
+               num_blocks = (int)(1 << (window_bits - 14));
 
             else
                num_blocks = 1;
 
-            if (png_ptr->zlib_mem_level >= 7)
-               num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
+            mem_level =
+                png_ptr->zlib_mem_level >= png_ptr->zlib_text_mem_level ?
+                png_ptr->zlib_mem_level : png_ptr->zlib_text_mem_level;
+
+            if (mem_level >= 7)
+               num_blocks += (int)(1 << (mem_level - 7));
 
             else
                num_blocks++;
@@ -277,7 +286,7 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)
       {
 #  ifndef PNG_USER_MEM_SUPPORTED
          if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
-            png_error(png_ptr, "Out of Memory"); /* Note "o" and "M" */
+            png_error(png_ptr, "Out of Memory"); /* Note "O" and "M" */
 
          else
             png_warning(png_ptr, "Out of Memory");
index 5ab9007a161696492b3a0f5b02f0f7dc7c3557fb..a50292a76ad6113ae57413914461d2dd2c48f0c6 100644 (file)
@@ -1026,8 +1026,10 @@ png_push_process_row(png_structp png_ptr)
 
    png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1);
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
    if (png_ptr->transformations)
       png_do_read_transformations(png_ptr);
+#endif
 
 #ifdef PNG_READ_INTERLACING_SUPPORTED
    /* Blow up interlaced rows to full size */
@@ -1288,7 +1290,7 @@ png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
       {
          PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
          png_error(png_ptr, "Out of place tEXt");
-         /*NOT REACHED*/
+         /* NOT REACHED */
       }
 
 #ifdef PNG_MAX_MALLOC_64K
@@ -1385,7 +1387,7 @@ png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
    {
       PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
       png_error(png_ptr, "Out of place zTXt");
-      /*NOT REACHED*/
+      /* NOT REACHED */
    }
 
 #ifdef PNG_MAX_MALLOC_64K
@@ -1589,7 +1591,7 @@ png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
    {
       PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
       png_error(png_ptr, "Out of place iTXt");
-      /*NOT REACHED*/
+      /* NOT REACHED */
    }
 
 #ifdef PNG_MAX_MALLOC_64K
index a7e3b5272700ddebe49f33fec0f7d55045ec66ff..5b4d2127cc9865c574f604c411b40de2cf4f8e74 100644 (file)
@@ -6,7 +6,7 @@
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
 #ifndef PNGPRIV_H
 #define PNGPRIV_H
 
+/* Feature Test Macros.  The following are defined here to ensure that correctly
+ * implemented libraries reveal the APIs libpng needs to build and hide those
+ * that are not needed and potentially damaging to the compilation.
+ *
+ * Feature Test Macros must be defined before any system header is included (see
+ * POSIX 1003.1 2.8.2 "POSIX Symbols."
+ *
+ * These macros only have an effect if the operating system supports either
+ * POSIX 1003.1 or C99, or both.  On other operating systems (particularly
+ * Windows/Visual Studio) there is no effect; the OS specific tests below are
+ * still required (as of 2011-05-02.)
+ */
+#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+
 /* This is required for the definition of abort(), used as a last ditch
  * error handler when all else fails.
  */
@@ -101,12 +115,27 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  define PNG_ZBUF_SIZE 65536L
 #endif
 
-/* If warnings or errors are turned off the code is disabled
- * or redirected here.
+/* PNG_STATIC is used to mark internal file scope functions if they need to be
+ * accessed for implementation tests (see the code in tests/?*).
  */
-#ifndef PNG_WARNINGS_SUPPORTED
-#  define png_warning(s1,s2) ((void)0)
-#  define png_chunk_warning(s1,s2) ((void)0)
+#ifndef PNG_STATIC
+#   define PNG_STATIC static
+#endif
+
+/* If warnings or errors are turned off the code is disabled or redirected here.
+ * From 1.5.4 functions have been added to allow very limited formatting of
+ * error and warning messages - this code will also be disabled here.
+ */
+#ifdef PNG_WARNINGS_SUPPORTED
+#  define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;
+#else
+#  define png_warning(s1,s2) ((void)(s1))
+#  define png_chunk_warning(s1,s2) ((void)(s1))
+#  define png_warning_parameter(p,number,string) ((void)0)
+#  define png_warning_parameter_unsigned(p,number,format,value) ((void)0)
+#  define png_warning_parameter_signed(p,number,format,value) ((void)0)
+#  define png_formatted_warning(pp,p,message) ((void)(pp))
+#  define PNG_WARNING_PARAMETERS(p)
 #endif
 #ifndef PNG_ERROR_TEXT_SUPPORTED
 #  define png_error(s1,s2) png_err(s1)
@@ -200,60 +229,28 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  define NOCHECK 0
 #  define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK))
 #  define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK))
-#  define png_strcpy  _fstrcpy
-#  define png_strncpy _fstrncpy   /* Added to v 1.2.6 */
 #  define png_strlen  _fstrlen
 #  define png_memcmp  _fmemcmp    /* SJT: added */
 #  define png_memcpy  _fmemcpy
 #  define png_memset  _fmemset
-#  define png_sprintf sprintf
 #else
 #  ifdef _WINDOWS_  /* Favor Windows over C runtime fns */
 #    define CVT_PTR(ptr)         (ptr)
 #    define CVT_PTR_NOCHECK(ptr) (ptr)
-#    define png_strcpy  lstrcpyA
-#    define png_strncpy lstrcpynA
 #    define png_strlen  lstrlenA
 #    define png_memcmp  memcmp
 #    define png_memcpy  CopyMemory
 #    define png_memset  memset
-#    define png_sprintf wsprintfA
 #  else
 #    define CVT_PTR(ptr)         (ptr)
 #    define CVT_PTR_NOCHECK(ptr) (ptr)
-#    define png_strcpy  strcpy
-#    define png_strncpy strncpy     /* Added to v 1.2.6 */
 #    define png_strlen  strlen
 #    define png_memcmp  memcmp      /* SJT: added */
 #    define png_memcpy  memcpy
 #    define png_memset  memset
-#    define png_sprintf sprintf
 #  endif
 #endif
 /* End of memory model/platform independent support */
-
-#ifndef PNG_NO_SNPRINTF
-#  ifdef _MSC_VER
-#    define png_snprintf _snprintf   /* Added to v 1.2.19 */
-#    define png_snprintf2 _snprintf
-#    define png_snprintf6 _snprintf
-#  else
-#    define png_snprintf snprintf   /* Added to v 1.2.19 */
-#    define png_snprintf2 snprintf
-#    define png_snprintf6 snprintf
-#  endif
-#else
-  /* You don't have or don't want to use snprintf().  Caution: Using
-   * sprintf instead of snprintf exposes your application to accidental
-   * or malevolent buffer overflows.  If you don't have snprintf()
-   * as a general rule you should provide one (you can get one from
-   * Portable OpenSSH).
-   */
-#  define png_snprintf(s1,n,fmt,x1) png_sprintf(s1,fmt,x1)
-#  define png_snprintf2(s1,n,fmt,x1,x2) png_sprintf(s1,fmt,x1,x2)
-#  define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \
-      png_sprintf(s1,fmt,x1,x2,x3,x4,x5,x6)
-#endif
 /* End of 1.5.0beta36 move from pngconf.h */
 
 /* CONSTANTS and UTILITY MACROS
@@ -261,12 +258,14 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
  */
 
 /* Various modes of operation.  Note that after an init, mode is set to
- * zero automatically when the structure is created.
+ * zero automatically when the structure is created.  Three of these
+ * are defined in png.h because they need to be visible to applications
+ * that call png_set_unknown_chunk().
  */
-#define PNG_HAVE_IHDR               0x01
-#define PNG_HAVE_PLTE               0x02
+/* #define PNG_HAVE_IHDR            0x01 (defined in png.h) */
+/* #define PNG_HAVE_PLTE            0x02 (defined in png.h) */
 #define PNG_HAVE_IDAT               0x04
-#define PNG_AFTER_IDAT              0x08 /* Have complete zlib datastream */
+/* #define PNG_AFTER_IDAT           0x08 (defined in png.h) */
 #define PNG_HAVE_IEND               0x10
 #define PNG_HAVE_gAMA               0x20
 #define PNG_HAVE_cHRM               0x40
@@ -286,10 +285,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_SWAP_BYTES          0x0010
 #define PNG_INVERT_MONO         0x0020
 #define PNG_QUANTIZE            0x0040
-#define PNG_BACKGROUND          0x0080
+#define PNG_COMPOSE             0x0080     /* Was PNG_BACKGROUND */
 #define PNG_BACKGROUND_EXPAND   0x0100
 #define PNG_EXPAND_16           0x0200     /* Added to libpng 1.5.2 */
-#define PNG_16_TO_8             0x0400
+#define PNG_16_TO_8             0x0400     /* Becomes 'chop' in 1.5.4 */
 #define PNG_RGBA                0x0800
 #define PNG_EXPAND              0x1000
 #define PNG_GAMMA               0x2000
@@ -303,10 +302,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_RGB_TO_GRAY_ERR   0x200000L
 #define PNG_RGB_TO_GRAY_WARN  0x400000L
 #define PNG_RGB_TO_GRAY       0x600000L  /* two bits, RGB_TO_GRAY_ERR|WARN */
-                       /*     0x800000L     Unused */
+#define PNG_ENCODE_ALPHA      0x800000L  /* Added to libpng-1.5.4 */
 #define PNG_ADD_ALPHA         0x1000000L  /* Added to libpng-1.2.7 */
 #define PNG_EXPAND_tRNS       0x2000000L  /* Added to libpng-1.2.9 */
-                       /*   0x4000000L  unused */
+#define PNG_SCALE_16_TO_8     0x4000000L  /* Added to libpng-1.5.4 */
                        /*   0x8000000L  unused */
                        /*  0x10000000L  unused */
                        /*  0x20000000L  unused */
@@ -333,9 +332,9 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200
 #define PNG_FLAG_CRC_CRITICAL_USE         0x0400
 #define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800
-                                /*        0x1000  unused */
-                                /*        0x2000  unused */
-                                /*        0x4000  unused */
+#define PNG_FLAG_ASSUME_sRGB              0x1000  /* Added to libpng-1.5.4 */
+#define PNG_FLAG_OPTIMIZE_ALPHA           0x2000  /* Added to libpng-1.5.4 */
+#define PNG_FLAG_DETECT_UNINITIALIZED     0x4000  /* Added to libpng-1.5.4 */
 #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000L
 #define PNG_FLAG_KEEP_UNSAFE_CHUNKS       0x10000L
 #define PNG_FLAG_LIBRARY_MISMATCH         0x20000L
@@ -345,13 +344,13 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
                                   /*      0x200000L  unused */
                                   /*      0x400000L  unused */
 #define PNG_FLAG_BENIGN_ERRORS_WARN       0x800000L  /* Added to libpng-1.4.0 */
-                                  /*     0x1000000L  unused */
-                                  /*     0x2000000L  unused */
-                                  /*     0x4000000L  unused */
-                                  /*     0x8000000L  unused */
-                                  /*    0x10000000L  unused */
-                                  /*    0x20000000L  unused */
-                                  /*    0x40000000L  unused */
+#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY    0x1000000L  /* 5 lines added */
+#define PNG_FLAG_ZTXT_CUSTOM_LEVEL       0x2000000L  /* to libpng-1.5.4 */
+#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL   0x4000000L
+#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000L
+#define PNG_FLAG_ZTXT_CUSTOM_METHOD      0x10000000L
+                                  /*     0x20000000L  unused */
+                                  /*     0x40000000L  unused */
 
 #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
                                      PNG_FLAG_CRC_ANCILLARY_NOWARN)
@@ -460,6 +459,11 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp,
 #define PNG_tRNS PNG_CONST png_byte png_tRNS[5] = {116,  82,  78,  83, '\0'}
 #define PNG_zTXt PNG_CONST png_byte png_zTXt[5] = {122,  84,  88, 116, '\0'}
 
+/* Gamma values (new at libpng-1.5.4): */
+#define PNG_GAMMA_MAC_OLD 151724  /* Assume '1.8' is really 2.2/1.45! */
+#define PNG_GAMMA_MAC_INVERSE 65909
+#define PNG_GAMMA_sRGB_INVERSE 45455
+
 
 /* Inhibit C++ name-mangling for libpng functions but not for system calls. */
 #ifdef __cplusplus
@@ -472,6 +476,12 @@ extern "C" {
  * be found in the files where the functions are located.
  */
 
+/* Check the user version string for compatibility, returns false if the version
+ * numbers aren't compatible.
+ */
+PNG_EXTERN int png_user_version_check(png_structp png_ptr,
+   png_const_charp user_png_ver);
+
 /* Allocate memory for an internal libpng struct */
 PNG_EXTERN PNG_FUNCTION(png_voidp,png_create_struct,PNGARG((int type)),
    PNG_ALLOCATED);
@@ -540,8 +550,7 @@ PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
     png_size_t length));
 
 /* Decompress data in a chunk that uses compression */
-#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \
-    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+#if defined(PNG_READ_COMPRESSED_TEXT_SUPPORTED)
 PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr,
     int comp_type, png_size_t chunklength, png_size_t prefix_length,
     png_size_t *data_length));
@@ -644,6 +653,7 @@ PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr,
     png_const_uint_16p hist, int num_hist));
 #endif
 
+/* Chunks that have keywords */
 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
     defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
 PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
@@ -734,17 +744,17 @@ PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
 PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
     png_row_infop row_info));
 
-/* Write out the filtered row. */
-PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
-    png_bytep filtered_row));
 /* Finish a row while reading, dealing with interlacing passes, etc. */
 PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
 
 /* Initialize the row buffers, etc. */
 PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* Optional call to update the users info structure */
 PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
     png_infop info_ptr));
+#endif
 
 /* These are the functions that do the transformations */
 #ifdef PNG_READ_FILLER_SUPPORTED
@@ -816,7 +826,12 @@ PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info,
     png_bytep row));
 #endif
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+PNG_EXTERN void png_do_scale_16_to_8 PNGARG((png_row_infop row_info,
+    png_bytep row));
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
 PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info,
     png_bytep row));
 #endif
@@ -847,26 +862,20 @@ PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info,
     png_bytep row, png_const_color_8p bit_depth));
 #endif
 
-#ifdef PNG_READ_BACKGROUND_SUPPORTED
-#  ifdef PNG_READ_GAMMA_SUPPORTED
-PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info,
-    png_bytep row, png_const_color_16p trans_color,
-    png_const_color_16p background, png_const_color_16p background_1,
-    png_const_bytep gamma_table, png_const_bytep gamma_from_1,
-    png_const_bytep gamma_to_1, png_const_uint_16pp gamma_16,
-    png_const_uint_16pp gamma_16_from_1, png_const_uint_16pp gamma_16_to_1,
-    int gamma_shift));
-#  else
-PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info,
-    png_bytep row, png_const_color_16p trans_color,
-    png_const_color_16p background));
-#  endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+PNG_EXTERN void png_do_compose PNGARG((png_row_infop row_info,
+    png_bytep row, png_structp png_ptr));
 #endif
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
 PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info,
-    png_bytep row, png_const_bytep gamma_table,
-    png_const_uint_16pp gamma_16_table, int gamma_shift));
+    png_bytep row, png_structp png_ptr));
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+PNG_EXTERN void png_do_encode_alpha PNGARG((png_row_infop row_info,
+   png_bytep row, png_structp png_ptr));
 #endif
 
 #ifdef PNG_READ_EXPAND_SUPPORTED
@@ -986,10 +995,16 @@ PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
     png_const_bytep chunk_name));
 
 /* Handle the transformations for reading and writing */
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+#endif
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
 PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
+#endif
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
+#endif
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
 PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
@@ -1086,6 +1101,76 @@ PNG_EXTERN PNG_FUNCTION(void, png_fixed_error, (png_structp png_ptr,
    png_const_charp name),PNG_NORETURN);
 #endif
 
+/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite
+ * the end.  Always leaves the buffer nul terminated.  Never errors out (and
+ * there is no error code.)
+ */
+PNG_EXTERN size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos,
+    png_const_charp string);
+
+/* Various internal functions to handle formatted warning messages, currently
+ * only implemented for warnings.
+ */
+#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Utility to dump an unsigned value into a buffer, given a start pointer and
+ * and end pointer (which should point just *beyond* the end of the buffer!)
+ * Returns the pointer to the start of the formatted string.  This utility only
+ * does unsigned values.
+ */
+PNG_EXTERN png_charp png_format_number(png_const_charp start, png_charp end,
+   int format, png_alloc_size_t number);
+
+/* Convenience macro that takes an array: */
+#define PNG_FORMAT_NUMBER(buffer,format,number) \
+   png_format_number(buffer, buffer + (sizeof buffer), format, number)
+
+/* Suggested size for a number buffer (enough for 64 bits and a sign!) */
+#define PNG_NUMBER_BUFFER_SIZE 24
+
+/* These are the integer formats currently supported, the name is formed from
+ * the standard printf(3) format string.
+ */
+#define PNG_NUMBER_FORMAT_u     1 /* chose unsigned API! */
+#define PNG_NUMBER_FORMAT_02u   2
+#define PNG_NUMBER_FORMAT_d     1 /* chose signed API! */
+#define PNG_NUMBER_FORMAT_02d   2
+#define PNG_NUMBER_FORMAT_x     3
+#define PNG_NUMBER_FORMAT_02x   4
+#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */
+#endif
+
+#ifdef PNG_WARNINGS_SUPPORTED
+/* New defines and members adding in libpng-1.5.4 */
+#  define PNG_WARNING_PARAMETER_SIZE 32
+#  define PNG_WARNING_PARAMETER_COUNT 8
+
+/* An l-value of this type has to be passed to the APIs below to cache the
+ * values of the parameters to a formatted warning message.
+ */
+typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][
+   PNG_WARNING_PARAMETER_SIZE];
+
+PNG_EXTERN void png_warning_parameter(png_warning_parameters p, int number,
+    png_const_charp string);
+    /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters,
+     * including the trailing '\0'.
+     */
+PNG_EXTERN void png_warning_parameter_unsigned(png_warning_parameters p,
+    int number, int format, png_alloc_size_t value);
+    /* Use png_alloc_size_t because it is an unsigned type as big as any we
+     * need to output.  Use the following for a signed value.
+     */
+PNG_EXTERN void png_warning_parameter_signed(png_warning_parameters p,
+    int number, int format, png_int_32 value);
+
+PNG_EXTERN void png_formatted_warning(png_structp png_ptr,
+    png_warning_parameters p, png_const_charp message);
+    /* 'message' follows the X/Open approach of using @1, @2 to insert
+     * parameters previously supplied using the above functions.  Errors in
+     * specifying the paramters will simple result in garbage substitutions.
+     */
+#endif
+
 /* ASCII to FP interfaces, currently only implemented if sCAL
  * support is required.
  */
@@ -1148,8 +1233,18 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr,
 #define PNG_FP_SAW_DOT   16  /* Saw a dot in current state */
 #define PNG_FP_SAW_E     32  /* Saw an E (or e) in current state */
 #define PNG_FP_SAW_ANY   60  /* Saw any of the above 4 */
+
+/* These three values don't affect the parser.  They are set but not used.
+ */
 #define PNG_FP_WAS_VALID 64  /* Preceding substring is a valid fp number */
-#define PNG_FP_INVALID  128  /* Available for callers as a distinct value */
+#define PNG_FP_NEGATIVE 128  /* A negative number, including "-0" */
+#define PNG_FP_NONZERO  256  /* A non-zero value */
+#define PNG_FP_STICKY   448  /* The above three flags */
+
+/* This is available for the caller to store in 'state' if required.  Do not
+ * call the parser after setting it (the parser sometimes clears it.)
+ */
+#define PNG_FP_INVALID  512  /* Available for callers as a distinct value */
 
 /* Result codes for the parser (boolean - true meants ok, false means
  * not ok yet.)
@@ -1157,6 +1252,20 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr,
 #define PNG_FP_MAYBE      0  /* The number may be valid in the future */
 #define PNG_FP_OK         1  /* The number is valid */
 
+/* Tests on the sticky non-zero and negative flags.  To pass these checks
+ * the state must also indicate that the whole number is valid - this is
+ * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this
+ * is equivalent to PNG_FP_OK above.)
+ */
+#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO)
+   /* NZ_MASK: the string is valid and a non-zero negative value */
+#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO)
+   /* Z MASK: the string is valid and a non-zero value. */
+   /* PNG_FP_SAW_DIGIT: the string is valid. */
+#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)
+#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)
+#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)
 /* The actual parser.  This can be called repeatedly, it updates
  * the index into the string and the state variable (which must
  * be initialzed to 0).  It returns a result code, as above.  There
@@ -1176,7 +1285,10 @@ PNG_EXTERN int png_check_fp_number PNGARG((png_const_charp string,
     png_size_t size, int *statep, png_size_tp whereami));
 
 /* This is the same but it checks a complete string and returns true
- * only if it just contains a floating point number.
+ * only if it just contains a floating point number.  As of 1.5.4 this
+ * function also returns the state at the end of parsing the number if
+ * it was valid (otherwise it returns 0.)  This can be used for testing
+ * for negative or zero values using the sticky flag.
  */
 PNG_EXTERN int png_check_fp_string PNGARG((png_const_charp string,
     png_size_t size));
index aa84001c4523559fcf4857ab26eb2fdafdb1e187..be3df47693d48366b77d73d5a75697a1a4a4e1f3 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngread.c - read a PNG file
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -47,12 +47,10 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
 
 #ifdef PNG_SETJMP_SUPPORTED
 #ifdef USE_FAR_KEYWORD
-   jmp_buf png_jmpbuf;
+   jmp_buf tmp_jmpbuf;
 #endif
 #endif
 
-   int i;
-
    png_debug(1, "in png_create_read_struct");
 
 #ifdef PNG_USER_MEM_SUPPORTED
@@ -85,13 +83,13 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    encounter a png_error() will longjmp here.  Since the jmpbuf is
    then meaningless we abort instead of returning. */
 #ifdef USE_FAR_KEYWORD
-   if (setjmp(png_jmpbuf))
+   if (setjmp(tmp_jmpbuf))
 #else
    if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */
 #endif
       PNG_ABORT();
 #ifdef USE_FAR_KEYWORD
-   png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
 #endif
 #endif /* PNG_SETJMP_SUPPORTED */
 
@@ -101,54 +99,9 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
 
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   if (user_png_ver)
-   {
-      i = 0;
-
-      do
-      {
-         if (user_png_ver[i] != png_libpng_ver[i])
-            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-      } while (png_libpng_ver[i++]);
-   }
-
-   else
-      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-
-
-   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
-   {
-     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
-      * we must recompile any applications that use any older library version.
-      * For versions after libpng 1.0, we will be compatible, so we need
-      * only check the first digit.
-      */
-      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
-          (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
-          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
-      {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         char msg[80];
-         if (user_png_ver)
-         {
-            png_snprintf2(msg, 80,
-                "Application built with libpng-%.20s"
-                " but running with %.20s",
-                user_png_ver,
-                png_libpng_ver);
-            png_warning(png_ptr, msg);
-         }
-#else
-         png_warning(png_ptr,
-             "Incompatible libpng version in application and library");
-#endif
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-         png_ptr->flags = 0;
-#endif
-
-         png_cleanup_needed = 1;
-      }
-   }
+   /* Call the general version checker (shared with read and write code): */
+   if (!png_user_version_check(png_ptr, user_png_ver))
+      png_cleanup_needed = 1;
 
    if (!png_cleanup_needed)
    {
@@ -457,7 +410,11 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr)
           "Ignoring extra png_read_update_info() call;"
           " row buffer not reallocated");
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
    png_read_transform_info(png_ptr, info_ptr);
+#else
+   PNG_UNUSED(info_ptr)
+#endif
 }
 
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
@@ -704,8 +661,10 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
 #endif
 
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
    if (png_ptr->transformations)
       png_do_read_transformations(png_ptr);
+#endif
 
 #ifdef PNG_READ_INTERLACING_SUPPORTED
    /* Blow up interlaced rows to full size */
@@ -1163,7 +1122,9 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
    jmp_buf tmp_jmp;
 #endif
    png_error_ptr error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    png_error_ptr warning_fn;
+#endif
    png_voidp error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    png_free_ptr free_fn;
@@ -1249,10 +1210,6 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
 #endif
 #endif
 
-#ifdef PNG_TIME_RFC1123_SUPPORTED
-   png_free(png_ptr, png_ptr->time_buffer);
-#endif
-
    inflateEnd(&png_ptr->zstream);
 
 #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
@@ -1269,11 +1226,13 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
     * being used again.
     */
 #ifdef PNG_SETJMP_SUPPORTED
-   png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
 #endif
 
    error_fn = png_ptr->error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    warning_fn = png_ptr->warning_fn;
+#endif
    error_ptr = png_ptr->error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    free_fn = png_ptr->free_fn;
@@ -1282,14 +1241,16 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
    png_memset(png_ptr, 0, png_sizeof(png_struct));
 
    png_ptr->error_fn = error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    png_ptr->warning_fn = warning_fn;
+#endif
    png_ptr->error_ptr = error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    png_ptr->free_fn = free_fn;
 #endif
 
 #ifdef PNG_SETJMP_SUPPORTED
-   png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
+   png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf));
 #endif
 
 }
@@ -1325,8 +1286,22 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
 
    /* -------------- image transformations start here ------------------- */
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-   /* Tell libpng to strip 16 bit/color files down to 8 bits per color.
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+   /* Tell libpng to strip 16-bit/color files down to 8 bits per color.
+    */
+   if (transforms & PNG_TRANSFORM_SCALE_16)
+   {
+     /* Added at libpng-1.5.4. "strip_16" produces the same result that it
+      * did in earlier versions, while "scale_16" is now more accurate.
+      */
+      png_set_scale_16(png_ptr);
+   }
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+   /* If both SCALE and STRIP are required pngrtran will effectively cancel the
+    * latter by doing SCALE first.  This is ok and allows apps not to check for
+    * which is supported to get the right answer.
     */
    if (transforms & PNG_TRANSFORM_STRIP_16)
       png_set_strip_16(png_ptr);
@@ -1407,7 +1382,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
 #endif
 
 #ifdef PNG_READ_SWAP_SUPPORTED
-   /* Swap bytes of 16 bit files to least significant byte first */
+   /* Swap bytes of 16-bit files to least significant byte first */
    if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
 #endif
@@ -1426,6 +1401,12 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
       png_set_gray_to_rgb(png_ptr);
 #endif
 
+/* Added at libpng-1.5.4 */
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+   if (transforms & PNG_TRANSFORM_EXPAND_16)
+      png_set_expand_16(png_ptr);
+#endif
+
    /* We don't handle adding filler bytes */
 
    /* We use png_read_image and rely on that for interlace handling, but we also
index de5871add02319793b487e5f07625283b67e9d9a..4e0401aa9f049c274a38a7ac04bacbffdd5f65b5 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngrtran.c - transforms the data in a row for PNG readers
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -106,12 +106,18 @@ png_set_background_fixed(png_structp png_ptr,
       return;
    }
 
-   png_ptr->transformations |= PNG_BACKGROUND;
+   png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
+   png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+   png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
    png_memcpy(&(png_ptr->background), background_color,
       png_sizeof(png_color_16));
    png_ptr->background_gamma = background_gamma;
    png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
-   png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+   if (need_expand)
+      png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
+   else
+      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
 }
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -126,8 +132,25 @@ png_set_background(png_structp png_ptr,
 #  endif  /* FLOATING_POINT */
 #endif /* READ_BACKGROUND */
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-/* Strip 16 bit depth files to 8 bit depth */
+/* Scale 16-bit depth files to 8-bit depth.  If both of these are set then the
+ * one that pngrtran does first (scale) happens.  This is necessary to allow the
+ * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
+ */
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+void PNGAPI
+png_set_scale_16(png_structp png_ptr)
+{
+   png_debug(1, "in png_set_scale_16");
+
+   if (png_ptr == NULL)
+      return;
+
+   png_ptr->transformations |= PNG_SCALE_16_TO_8;
+}
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+/* Chop 16-bit depth files to 8-bit depth */
 void PNGAPI
 png_set_strip_16(png_structp png_ptr)
 {
@@ -137,7 +160,6 @@ png_set_strip_16(png_structp png_ptr)
       return;
 
    png_ptr->transformations |= PNG_16_TO_8;
-   png_ptr->transformations &= ~PNG_EXPAND_16;
 }
 #endif
 
@@ -154,8 +176,190 @@ png_set_strip_alpha(png_structp png_ptr)
 }
 #endif
 
+#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
+static png_fixed_point
+translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma,
+   int is_screen)
+{
+   /* Check for flag values.  The main reason for having the old Mac value as a
+    * flag is that it is pretty near impossible to work out what the correct
+    * value is from Apple documentation - a working Mac system is needed to
+    * discover the value!
+    */
+   if (output_gamma == PNG_DEFAULT_sRGB ||
+      output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
+   {
+      /* If there is no sRGB support this just sets the gamma to the standard
+       * sRGB value.  (This is a side effect of using this function!)
+       */
+#     ifdef PNG_READ_sRGB_SUPPORTED
+         png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
+#     endif
+      if (is_screen)
+         output_gamma = PNG_GAMMA_sRGB;
+      else
+         output_gamma = PNG_GAMMA_sRGB_INVERSE;
+   }
+
+   else if (output_gamma == PNG_GAMMA_MAC_18 ||
+      output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
+   {
+      if (is_screen)
+         output_gamma = PNG_GAMMA_MAC_OLD;
+      else
+         output_gamma = PNG_GAMMA_MAC_INVERSE;
+   }
+
+   return output_gamma;
+}
+
+#  ifdef PNG_FLOATING_POINT_SUPPORTED
+static png_fixed_point
+convert_gamma_value(png_structp png_ptr, double output_gamma)
+{
+   /* The following silently ignores cases where fixed point (times 100,000)
+    * gamma values are passed to the floating point API.  This is safe and it
+    * means the fixed point constants work just fine with the floating point
+    * API.  The alternative would just lead to undetected errors and spurious
+    * bug reports.  Negative values fail inside the _fixed API unless they
+    * correspond to the flag values.
+    */
+   if (output_gamma > 0 && output_gamma < 128)
+      output_gamma *= PNG_FP_1;
+
+   /* This preserves -1 and -2 exactly: */
+   output_gamma = floor(output_gamma + .5);
+
+   if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)
+      png_fixed_error(png_ptr, "gamma value");
+
+   return (png_fixed_point)output_gamma;
+}
+#  endif
+#endif /* READ_ALPHA_MODE || READ_GAMMA */
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+void PNGFAPI
+png_set_alpha_mode_fixed(png_structp png_ptr, int mode,
+   png_fixed_point output_gamma)
+{
+   int compose = 0;
+   png_fixed_point file_gamma;
+
+   png_debug(1, "in png_set_alpha_mode");
+
+   if (png_ptr == NULL)
+      return;
+
+   output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
+
+   /* Validate the value to ensure it is in a reasonable range. The value
+    * is expected to be 1 or greater, but this range test allows for some
+    * viewing correction values.  The intent is to weed out users of this API
+    * who use the inverse of the gamma value accidentally!  Since some of these
+    * values are reasonable this may have to be changed.
+    */
+   if (output_gamma < 70000 || output_gamma > 300000)
+      png_error(png_ptr, "output gamma out of expected range");
+
+   /* The default file gamma is the inverse of the output gamma; the output
+    * gamma may be changed below so get the file value first:
+    */
+   file_gamma = png_reciprocal(output_gamma);
+
+   /* There are really 8 possibilities here, composed of any combination
+    * of:
+    *
+    *    premultiply the color channels
+    *    do not encode non-opaque pixels
+    *    encode the alpha as well as the color channels
+    *
+    * The differences disappear if the input/output ('screen') gamma is 1.0,
+    * because then the encoding is a no-op and there is only the choice of
+    * premultiplying the color channels or not.
+    *
+    * png_set_alpha_mode and png_set_background interact because both use
+    * png_compose to do the work.  Calling both is only useful when
+    * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along
+    * with a default gamma value.  Otherwise PNG_COMPOSE must not be set.
+    */
+   switch (mode)
+   {
+      case PNG_ALPHA_PNG:        /* default: png standard */
+         /* No compose, but it may be set by png_set_background! */
+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+         break;
+
+      case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
+         compose = 1;
+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+         /* The output is linear: */
+         output_gamma = PNG_FP_1;
+         break;
+
+      case PNG_ALPHA_OPTIMIZED:  /* associated, non-opaque pixels linear */
+         compose = 1;
+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+         png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;
+         /* output_gamma records the encoding of opaque pixels! */
+         break;
+
+      case PNG_ALPHA_BROKEN:     /* associated, non-linear, alpha encoded */
+         compose = 1;
+         png_ptr->transformations |= PNG_ENCODE_ALPHA;
+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+         break;
+
+      default:
+         png_error(png_ptr, "invalid alpha mode");
+   }
+
+   /* Only set the default gamma if the file gamma has not been set (this has
+    * the side effect that the gamma in a second call to png_set_alpha_mode will
+    * be ignored.)
+    */
+   if (png_ptr->gamma == 0)
+      png_ptr->gamma = file_gamma;
+
+   /* But always set the output gamma: */
+   png_ptr->screen_gamma = output_gamma;
+
+   /* Finally, if pre-multiplying, set the background fields to achieve the
+    * desired result.
+    */
+   if (compose)
+   {
+      /* And obtain alpha pre-multiplication by composing on black: */
+      png_memset(&png_ptr->background, 0, sizeof png_ptr->background);
+      png_ptr->background_gamma = png_ptr->gamma; /* just in case */
+      png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
+      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
+
+      if (png_ptr->transformations & PNG_COMPOSE)
+         png_error(png_ptr,
+            "conflicting calls to set alpha mode and background");
+
+      png_ptr->transformations |= PNG_COMPOSE;
+   }
+
+   /* New API, make sure apps call the correct initializers: */
+   png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
+}
+
+#  ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_alpha_mode(png_structp png_ptr, int mode, double output_gamma)
+{
+   png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
+      output_gamma));
+}
+#  endif
+#endif
+
 #ifdef PNG_READ_QUANTIZE_SUPPORTED
-/* Dither file to 8 bit.  Supply a palette, the current number
+/* Dither file to 8-bit.  Supply a palette, the current number
  * of elements in the palette, the maximum number of elements
  * allowed, and a histogram if possible.  If the current number
  * of colors is greater then the maximum number, the palette will be
@@ -561,30 +765,6 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
 #endif /* PNG_READ_QUANTIZE_SUPPORTED */
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
-/* Transform the image from the file_gamma to the screen_gamma.  We
- * only do transformations on images where the file_gamma and screen_gamma
- * are not close reciprocals, otherwise it slows things down slightly, and
- * also needlessly introduces small errors.
- *
- * We will turn off gamma transformation later if no semitransparent entries
- * are present in the tRNS array for palette images.  We can't do it here
- * because we don't necessarily have the tRNS chunk yet.
- */
-static int /* PRIVATE */
-png_gamma_threshold(png_fixed_point scrn_gamma, png_fixed_point file_gamma)
-{
-   /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
-    * correction as a difference of the overall transform from 1.0
-    *
-    * We want to compare the threshold with s*f - 1, if we get
-    * overflow here it is because of wacky gamma values so we
-    * turn on processing anyway.
-    */
-   png_fixed_point gtest;
-   return !png_muldiv(&gtest, scrn_gamma, file_gamma, PNG_FP_1) ||
-       png_gamma_significant(gtest);
-}
-
 void PNGFAPI
 png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma,
    png_fixed_point file_gamma)
@@ -594,10 +774,32 @@ png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma,
    if (png_ptr == NULL)
       return;
 
-   if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
-       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
-       png_gamma_threshold(scrn_gamma, file_gamma))
-      png_ptr->transformations |= PNG_GAMMA;
+   /* New in libpng-1.5.4 - reserve particular negative values as flags. */
+   scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
+   file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
+
+#if PNG_LIBPNG_VER >= 10600
+   /* Checking the gamma values for being >0 was added in 1.5.4 along with the
+    * premultiplied alpha support; this actually hides an undocumented feature
+    * of the previous implementation which allowed gamma processing to be
+    * disabled in background handling.  There is no evidence (so far) that this
+    * was being used; however, png_set_background itself accepted and must still
+    * accept '0' for the gamma value it takes, because it isn't always used.
+    *
+    * Since this is an API change (albeit a very minor one that removes an
+    * undocumented API feature) it will not be made until libpng-1.6.0.
+    */
+   if (file_gamma <= 0)
+      png_error(png_ptr, "invalid file gamma in png_set_gamma");
+
+   if (scrn_gamma <= 0)
+      png_error(png_ptr, "invalid screen gamma in png_set_gamma");
+#endif
+
+   /* Set the gamma values unconditionally - this overrides the value in the PNG
+    * file if a gAMA chunk was present.  png_set_alpha_mode provides a
+    * different, easier, way to default the file gamma.
+    */
    png_ptr->gamma = file_gamma;
    png_ptr->screen_gamma = scrn_gamma;
 }
@@ -606,9 +808,8 @@ png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma,
 void PNGAPI
 png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
 {
-   png_set_gamma_fixed(png_ptr,
-      png_fixed(png_ptr, scrn_gamma, "png_set_gamma screen gamma"),
-      png_fixed(png_ptr, file_gamma, "png_set_gamma file gamma"));
+   png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
+      convert_gamma_value(png_ptr, file_gamma));
 }
 #  endif /* FLOATING_POINT_SUPPORTED */
 #endif /* READ_GAMMA */
@@ -688,7 +889,7 @@ png_set_tRNS_to_alpha(png_structp png_ptr)
 #endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
 
 #ifdef PNG_READ_EXPAND_16_SUPPORTED
-/* Expand to 16 bit channels, expand the tRNS chunk too (because otherwise
+/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise
  * it may not work correctly.)
  */
 void PNGAPI
@@ -700,9 +901,10 @@ png_set_expand_16(png_structp png_ptr)
       return;
 
    png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);
-   png_ptr->transformations &= ~PNG_16_TO_8;
-
    png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
+
+   /* New API, make sure apps call the correct initializers: */
+   png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
 }
 #endif
 
@@ -762,30 +964,38 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
    }
 #endif
    {
-      png_uint_16 red_int, green_int;
-      if (red < 0 || green < 0)
+      if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)
       {
-         red_int   =  6968; /* .212671 * 32768 + .5 */
-         green_int = 23434; /* .715160 * 32768 + .5 */
-      }
+         png_uint_16 red_int, green_int;
 
-      else if (red + green < 100000L)
-      {
          red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
          green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
+
+         png_ptr->rgb_to_gray_red_coeff   = red_int;
+         png_ptr->rgb_to_gray_green_coeff = green_int;
+         png_ptr->rgb_to_gray_blue_coeff  =
+          (png_uint_16)(32768 - red_int - green_int);
       }
 
       else
       {
-         png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
-         red_int   =  6968;
-         green_int = 23434;
-      }
+         if (red >= 0 && green >= 0)
+            png_warning(png_ptr,
+               "ignoring out of range rgb_to_gray coefficients");
 
-      png_ptr->rgb_to_gray_red_coeff   = red_int;
-      png_ptr->rgb_to_gray_green_coeff = green_int;
-      png_ptr->rgb_to_gray_blue_coeff  =
-          (png_uint_16)(32768 - red_int - green_int);
+         /* Use the defaults, from the cHRM chunk if set, else the built in Rec
+          * 709 values (which correspond to sRGB, so we don't have to worry
+          * about the sRGB chunk!)
+          */
+         if (png_ptr->rgb_to_gray_red_coeff == 0 &&
+            png_ptr->rgb_to_gray_green_coeff == 0 &&
+            png_ptr->rgb_to_gray_blue_coeff == 0)
+         {
+            png_ptr->rgb_to_gray_red_coeff   = 6968;  /* .212671 * 32768 + .5 */
+            png_ptr->rgb_to_gray_green_coeff = 23434; /* .715160 * 32768 + .5 */
+            png_ptr->rgb_to_gray_blue_coeff  = 2366;
+         }
+      }
    }
 }
 
@@ -827,55 +1037,160 @@ png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
 }
 #endif
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+#ifdef PNG_READ_GAMMA_SUPPORTED
+/* In the case of gamma transformations only do transformations on images where
+ * the [file] gamma and screen_gamma are not close reciprocals, otherwise it
+ * slows things down slightly, and also needlessly introduces small errors.
+ */
+static int /* PRIVATE */
+png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
+{
+   /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
+    * correction as a difference of the overall transform from 1.0
+    *
+    * We want to compare the threshold with s*f - 1, if we get
+    * overflow here it is because of wacky gamma values so we
+    * turn on processing anyway.
+    */
+   png_fixed_point gtest;
+   return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||
+       png_gamma_significant(gtest);
+}
+#endif
+
 /* Initialize everything needed for the read.  This includes modifying
  * the palette.
  */
-void /* PRIVATE */
-png_init_read_transformations(png_structp png_ptr)
+
+/*For the moment 'png_init_palette_transformations' and
+ * 'png_init_rgb_transformations' only do some flag canceling optimizations.
+ * The intent is that these two routines should have palette or rgb operations
+ * extracted from 'png_init_read_transformations'.
+ */
+static void /* PRIVATE */
+png_init_palette_transformations(png_structp png_ptr)
 {
-   png_debug(1, "in png_init_read_transformations");
+   /* Called to handle the (input) palette case.  In png_do_read_transformations
+    * the first step is to expand the palette if requested, so this code must
+    * take care to only make changes that are invariant with respect to the
+    * palette expansion, or only do them if there is no expansion.
+    *
+    * STRIP_ALPHA has already been handled in the caller (by setting num_trans
+    * to 0.)
+    */
+   int input_has_alpha = 0;
+   int input_has_transparency = 0;
 
-  {
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
-    defined(PNG_READ_SHIFT_SUPPORTED) || \
-    defined(PNG_READ_GAMMA_SUPPORTED)
-   int color_type = png_ptr->color_type;
-#endif
+   if (png_ptr->num_trans > 0)
+   {
+      int i;
+
+      /* Ignore if all the entries are opaque (unlikely!) */
+      for (i=0; i<png_ptr->num_trans; ++i)
+         if (png_ptr->trans_alpha[i] == 255)
+            continue;
+         else if (png_ptr->trans_alpha[i] == 0)
+            input_has_transparency = 1;
+         else
+            input_has_alpha = 1;
+   }
+
+   /* If no alpha we can optimize. */
+   if (!input_has_alpha)
+   {
+      /* Any alpha means background and associative alpha processing is
+       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+       * and ENCODE_ALPHA are irrelevant.
+       */
+      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
+      if (!input_has_transparency)
+         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
+   }
 
 #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+   /* png_set_background handling - deals with the complexity of whether the
+    * background color is in the file format or the screen format in the case
+    * where an 'expand' will happen.
+    */
 
-#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
-   /* Detect gray background and attempt to enable optimization
-    * for gray --> RGB case
-    *
-    * Note:  if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
-    * RGB_ALPHA (in which case need_expand is superfluous anyway), the
-    * background color might actually be gray yet not be flagged as such.
-    * This is not a problem for the current code, which uses
-    * PNG_BACKGROUND_IS_GRAY only to decide when to do the
-    * png_do_gray_to_rgb() transformation.
+   /* The following code cannot be entered in the alpha pre-multiplication case
+    * because PNG_BACKGROUND_EXPAND is cancelled below.
     */
    if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
-       !(color_type & PNG_COLOR_MASK_COLOR))
+       (png_ptr->transformations & PNG_EXPAND))
    {
-      png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
-   }
+      {
+         png_ptr->background.red   =
+             png_ptr->palette[png_ptr->background.index].red;
+         png_ptr->background.green =
+             png_ptr->palette[png_ptr->background.index].green;
+         png_ptr->background.blue  =
+             png_ptr->palette[png_ptr->background.index].blue;
+
+#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
+        if (png_ptr->transformations & PNG_INVERT_ALPHA)
+        {
+           if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
+           {
+              /* Invert the alpha channel (in tRNS) unless the pixels are
+               * going to be expanded, in which case leave it for later
+               */
+              int i, istop = png_ptr->num_trans;
+
+              for (i=0; i<istop; i++)
+                 png_ptr->trans_alpha[i] = (png_byte)(255 -
+                    png_ptr->trans_alpha[i]);
+           }
+        }
+#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */
+      }
+   } /* background expand and (therefore) no alpha association. */
+#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */
+}
 
-   else if ((png_ptr->transformations & PNG_BACKGROUND) &&
-       !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
-       (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
-       png_ptr->background.red == png_ptr->background.green &&
-       png_ptr->background.red == png_ptr->background.blue)
+static void /* PRIVATE */
+png_init_rgb_transformations(png_structp png_ptr)
+{
+   /* Added to libpng-1.5.4: check the color type to determine whether there
+    * is any alpha or transparency in the image and simply cancel the
+    * background and alpha mode stuff if there isn't.
+    */
+   int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;
+   int input_has_transparency = png_ptr->num_trans > 0;
+
+   /* If no alpha we can optimize. */
+   if (!input_has_alpha)
    {
-      png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
-      png_ptr->background.gray = png_ptr->background.red;
+      /* Any alpha means background and associative alpha processing is
+       * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+       * and ENCODE_ALPHA are irrelevant.
+       */
+#     ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+#     endif
+
+      if (!input_has_transparency)
+         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
    }
-#endif
 
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+   /* png_set_background handling - deals with the complexity of whether the
+    * background color is in the file format or the screen format in the case
+    * where an 'expand' will happen.
+    */
+
+   /* The following code cannot be entered in the alpha pre-multiplication case
+    * because PNG_BACKGROUND_EXPAND is cancelled below.
+    */
    if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
-       (png_ptr->transformations & PNG_EXPAND))
+       (png_ptr->transformations & PNG_EXPAND) &&
+       !(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
+       /* i.e., GRAY or GRAY_ALPHA */
    {
-      if (!(color_type & PNG_COLOR_MASK_COLOR))  /* i.e., GRAY or GRAY_ALPHA */
       {
          /* Expand background and tRNS chunks */
          switch (png_ptr->bit_depth)
@@ -926,68 +1241,286 @@ png_init_read_transformations(png_structp png_ptr)
                break;
          }
       }
-      else if (color_type == PNG_COLOR_TYPE_PALETTE)
-      {
-         png_ptr->background.red   =
-             png_ptr->palette[png_ptr->background.index].red;
-         png_ptr->background.green =
-             png_ptr->palette[png_ptr->background.index].green;
-         png_ptr->background.blue  =
-             png_ptr->palette[png_ptr->background.index].blue;
+   } /* background expand and (therefore) no alpha association. */
+#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */
+}
 
-#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
-        if (png_ptr->transformations & PNG_INVERT_ALPHA)
-        {
-#ifdef PNG_READ_EXPAND_SUPPORTED
-           if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
-#endif
-           {
-              /* Invert the alpha channel (in tRNS) unless the pixels are
-               * going to be expanded, in which case leave it for later
-               */
-              int i, istop;
-              istop=(int)png_ptr->num_trans;
-              for (i=0; i<istop; i++)
-                 png_ptr->trans_alpha[i] = (png_byte)(255 -
-                    png_ptr->trans_alpha[i]);
-           }
-        }
-#endif
+void /* PRIVATE */
+png_init_read_transformations(png_structp png_ptr)
+{
+   png_debug(1, "in png_init_read_transformations");
+
+   /* This internal function is called from png_read_start_row in pngrutil.c
+    * and it is called before the 'rowbytes' calculation is done, so the code
+    * in here can change or update the transformations flags.
+    *
+    * First do updates that do not depend on the details of the PNG image data
+    * being processed.
+    */
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+   /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds
+    * png_set_alpha_mode and this is another source for a default file gamma so
+    * the test needs to be performed later - here.  In addition prior to 1.5.4
+    * the tests were repeated for the PALETTE color type here - this is no
+    * longer necessary (and doesn't seem to have been necessary before.)
+    */
+   {
+      /* The following temporary indicates if overall gamma correction is
+       * required.
+       */
+      int gamma_correction = 0;
 
+      if (png_ptr->gamma != 0) /* has been set */
+      {
+         if (png_ptr->screen_gamma != 0) /* screen set too */
+            gamma_correction = png_gamma_threshold(png_ptr->gamma,
+               png_ptr->screen_gamma);
+
+         else
+            /* Assume the output matches the input; a long time default behavior
+             * of libpng, although the standard has nothing to say about this.
+             */
+            png_ptr->screen_gamma = png_reciprocal(png_ptr->gamma);
       }
+
+      else if (png_ptr->screen_gamma != 0)
+         /* The converse - assume the file matches the screen, note that this
+          * perhaps undesireable default can (from 1.5.4) be changed by calling
+          * png_set_alpha_mode (even if the alpha handling mode isn't required
+          * or isn't changed from the default.)
+          */
+         png_ptr->gamma = png_reciprocal(png_ptr->screen_gamma);
+
+      else /* neither are set */
+         /* Just in case the following prevents any processing - file and screen
+          * are both assumed to be linear and there is no way to introduce a
+          * third gamma value other than png_set_background with 'UNIQUE', and,
+          * prior to 1.5.4
+          */
+         png_ptr->screen_gamma = png_ptr->gamma = PNG_FP_1;
+
+      /* Now turn the gamma transformation on or off as appropriate.  Notice
+       * that PNG_GAMMA just refers to the file->screen correction.  Alpha
+       * composition may independently cause gamma correction because it needs
+       * linear data (e.g. if the file has a gAMA chunk but the screen gamma
+       * hasn't been specified.)  In any case this flag may get turned off in
+       * the code immediately below if the transform can be handled outside the
+       * row loop.
+       */
+      if (gamma_correction)
+         png_ptr->transformations |= PNG_GAMMA;
+
+      else
+         png_ptr->transformations &= ~PNG_GAMMA;
    }
 #endif
 
-#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
-   png_ptr->background_1 = png_ptr->background;
+   /* Certain transformations have the effect of preventing other
+    * transformations that happen afterward in png_do_read_transformations,
+    * resolve the interdependencies here.  From the code of
+    * png_do_read_transformations the order is:
+    *
+    *  1) PNG_EXPAND (including PNG_EXPAND_tRNS)
+    *  2) PNG_STRIP_ALPHA (if no compose)
+    *  3) PNG_RGB_TO_GRAY
+    *  4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY
+    *  5) PNG_COMPOSE
+    *  6) PNG_GAMMA
+    *  7) PNG_STRIP_ALPHA (if compose)
+    *  8) PNG_ENCODE_ALPHA
+    *  9) PNG_SCALE_16_TO_8
+    * 10) PNG_16_TO_8
+    * 11) PNG_QUANTIZE (converts to palette)
+    * 12) PNG_EXPAND_16
+    * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY
+    * 14) PNG_INVERT_MONO
+    * 15) PNG_SHIFT
+    * 16) PNG_PACK
+    * 17) PNG_BGR
+    * 18) PNG_PACKSWAP
+    * 19) PNG_FILLER (includes PNG_ADD_ALPHA)
+    * 20) PNG_INVERT_ALPHA
+    * 21) PNG_SWAP_ALPHA
+    * 22) PNG_SWAP_BYTES
+    * 23) PNG_USER_TRANSFORM [must be last]
+    */
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
+      !(png_ptr->transformations & PNG_COMPOSE))
+   {
+      /* Stripping the alpha channel happens immediately after the 'expand'
+       * transformations, before all other transformation, so it cancels out
+       * the alpha handling.  It has the side effect negating the effect of
+       * PNG_EXPAND_tRNS too:
+       */
+      png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |
+         PNG_EXPAND_tRNS);
+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+
+      /* Kill the tRNS chunk itself too.  Prior to 1.5.4 this did not happen
+       * so transparency information would remain just so long as it wasn't
+       * expanded.  This produces unexpected API changes if the set of things
+       * that do PNG_EXPAND_tRNS changes (perfectly possible given the
+       * documentation - which says ask for what you want, accept what you
+       * get.)  This makes the behavior consistent from 1.5.4:
+       */
+      png_ptr->num_trans = 0;
+   }
+#endif /* STRIP_ALPHA supported, no COMPOSE */
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+   /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA
+    * settings will have no effect.
+    */
+   if (!png_gamma_significant(png_ptr->screen_gamma))
+   {
+      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
+      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
+   }
 #endif
-#ifdef PNG_READ_GAMMA_SUPPORTED
 
-   if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
-       && png_gamma_threshold(png_ptr->screen_gamma, png_ptr->gamma))
+#if defined(PNG_READ_EXPAND_SUPPORTED) && \
+   defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+   defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+   /* Detect gray background and attempt to enable optimization for
+    * gray --> RGB case.
+    *
+    * Note:  if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
+    * RGB_ALPHA (in which case need_expand is superfluous anyway), the
+    * background color might actually be gray yet not be flagged as such.
+    * This is not a problem for the current code, which uses
+    * PNG_BACKGROUND_IS_GRAY only to decide when to do the
+    * png_do_gray_to_rgb() transformation.
+    *
+    * TODO: this code needs to be revised to avoid the complexity and
+    * interdependencies.  The color type of the background should be recorded in
+    * png_set_background, along with the bit depth, then the code has a record
+    * of exactly what color space the background is currently in.
+    */
+   if (png_ptr->transformations & PNG_BACKGROUND_EXPAND)
+   {
+      /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
+       * the file was greyscale the background value is gray.
+       */
+      if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
+         png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+   }
+
+   else if (png_ptr->transformations & PNG_COMPOSE)
    {
-      int i, k;
-      k=0;
-      for (i=0; i<png_ptr->num_trans; i++)
+      /* PNG_COMPOSE: png_set_background was called with need_expand false,
+       * so the color is in the color space of the output or png_set_alpha_mode
+       * was called and the color is black.  Ignore RGB_TO_GRAY because that
+       * happens before GRAY_TO_RGB.
+       */
+      if (png_ptr->transformations & PNG_GRAY_TO_RGB)
       {
-        if (png_ptr->trans_alpha[i] != 0 && png_ptr->trans_alpha[i] != 0xff)
-           k=1; /* Partial transparency is present */
+         if (png_ptr->background.red == png_ptr->background.green &&
+             png_ptr->background.red == png_ptr->background.blue)
+         {
+            png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+            png_ptr->background.gray = png_ptr->background.red;
+         }
       }
-      if (k == 0)
-         png_ptr->transformations &= ~PNG_GAMMA;
    }
+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED (etc) */
+
+   /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations
+    * can be performed directly on the palette, and some (such as rgb to gray)
+    * can be optimized inside the palette.  This is particularly true of the
+    * composite (background and alpha) stuff, which can be pretty much all done
+    * in the palette even if the result is expanded to RGB or gray afterward.
+    *
+    * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and
+    * earlier and the palette stuff is actually handled on the first row.  This
+    * leads to the reported bug that the palette returned by png_get_PLTE is not
+    * updated.
+    */
+   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      png_init_palette_transformations(png_ptr);
 
-   if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
-       png_ptr->gamma != 0)
+   else
+      png_init_rgb_transformations(png_ptr);
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+   defined(PNG_READ_EXPAND_16_SUPPORTED)
+   if ((png_ptr->transformations & PNG_EXPAND_16) &&
+      (png_ptr->transformations & PNG_COMPOSE) &&
+      !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
+      png_ptr->bit_depth != 16)
+   {
+      /* TODO: fix this.  Because the expand_16 operation is after the compose
+       * handling the background color must be 8, not 16, bits deep, but the
+       * application will supply a 16-bit value so reduce it here.
+       *
+       * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at
+       * present, so that case is ok (until do_expand_16 is moved.)
+       *
+       * NOTE: this discards the low 16 bits of the user supplied background
+       * color, but until expand_16 works properly there is no choice!
+       */
+#     define CHOP(x) (x)=((png_uint_16)(((png_uint_32)(x)*255+32895) >> 16))
+      CHOP(png_ptr->background.red);
+      CHOP(png_ptr->background.green);
+      CHOP(png_ptr->background.blue);
+      CHOP(png_ptr->background.gray);
+#     undef CHOP
+   }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */
+
+   /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the
+    * background support (see the comments in scripts/pnglibconf.dfa), this
+    * allows pre-multiplication of the alpha channel to be implemented as
+    * compositing on black.  This is probably sub-optimal and has been done in
+    * 1.5.4 betas simply to enable external critique and testing (i.e. to
+    * implement the new API quickly, without lots of internal changes.)
+    */
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+#  ifdef PNG_READ_BACKGROUND_SUPPORTED
+      /* Includes ALPHA_MODE */
+      png_ptr->background_1 = png_ptr->background;
+#  endif
+
+   /* This needs to change - in the palette image case a whole set of tables are
+    * built when it would be quicker to just calculate the correct value for
+    * each palette entry directly.  Also, the test is too tricky - why check
+    * PNG_RGB_TO_GRAY if PNG_GAMMA is not set?  The answer seems to be that
+    * PNG_GAMMA is cancelled even if the gamma is known?  The test excludes the
+    * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction
+    * the gamma tables will not be built even if composition is required on a
+    * gamma encoded value.
+    *
+    * In 1.5.4 this is addressed below by an additional check on the individual
+    * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the
+    * tables.
+    */
+   if ((png_ptr->transformations & PNG_GAMMA)
+      || ((png_ptr->transformations & PNG_RGB_TO_GRAY)
+         && (png_gamma_significant(png_ptr->gamma) ||
+            png_gamma_significant(png_ptr->screen_gamma)))
+      || ((png_ptr->transformations & PNG_COMPOSE)
+         && (png_gamma_significant(png_ptr->gamma)
+            || png_gamma_significant(png_ptr->screen_gamma)
+#  ifdef PNG_READ_BACKGROUND_SUPPORTED
+            || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE
+               && png_gamma_significant(png_ptr->background_gamma))
+#  endif
+      )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA)
+         && png_gamma_significant(png_ptr->screen_gamma))
+      )
    {
       png_build_gamma_table(png_ptr, png_ptr->bit_depth);
 
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
-      if (png_ptr->transformations & PNG_BACKGROUND)
+      if (png_ptr->transformations & PNG_COMPOSE)
       {
-         if (color_type == PNG_COLOR_TYPE_PALETTE)
+         if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
          {
-            /* Could skip if no transparency */
+            /* We don't get to here unless there is a tRNS chunk with non-opaque
+             * entries - see the checking code at the start of this function.
+             */
             png_color back, back_1;
             png_colorp palette = png_ptr->palette;
             int num_palette = png_ptr->num_palette;
@@ -1032,13 +1565,6 @@ png_init_read_transformations(png_structp png_ptr)
                }
 
                if (png_gamma_significant(gs))
-               {
-                  back.red   = (png_byte)png_ptr->background.red;
-                  back.green = (png_byte)png_ptr->background.green;
-                  back.blue  = (png_byte)png_ptr->background.blue;
-               }
-
-               else
                {
                   back.red = png_gamma_8bit_correct(png_ptr->background.red,
                       gs);
@@ -1047,12 +1573,32 @@ png_init_read_transformations(png_structp png_ptr)
                   back.blue = png_gamma_8bit_correct(png_ptr->background.blue,
                       gs);
                }
-               back_1.red = png_gamma_8bit_correct(png_ptr->background.red, g);
-               back_1.green = png_gamma_8bit_correct(png_ptr->background.green,
-                   g);
-               back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
-                   g);
+
+               else
+               {
+                  back.red   = (png_byte)png_ptr->background.red;
+                  back.green = (png_byte)png_ptr->background.green;
+                  back.blue  = (png_byte)png_ptr->background.blue;
+               }
+
+               if (png_gamma_significant(g))
+               {
+                  back_1.red = png_gamma_8bit_correct(png_ptr->background.red,
+                     g);
+                  back_1.green = png_gamma_8bit_correct(
+                     png_ptr->background.green, g);
+                  back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
+                     g);
+               }
+
+               else
+               {
+                  back_1.red   = (png_byte)png_ptr->background.red;
+                  back_1.green = (png_byte)png_ptr->background.green;
+                  back_1.blue  = (png_byte)png_ptr->background.blue;
+               }
             }
+
             for (i = 0; i < num_palette; i++)
             {
                if (i < (int)png_ptr->num_trans &&
@@ -1086,19 +1632,18 @@ png_init_read_transformations(png_structp png_ptr)
                   palette[i].blue = png_ptr->gamma_table[palette[i].blue];
                }
             }
-            /* Prevent the transformations being done again, and make sure
-             * that the now spurious alpha channel is stripped - the code
-             * has just reduced background composition and gamma correction
-             * to a simple alpha channel strip.
+
+            /* Prevent the transformations being done again.
+             *
+             * NOTE: this is highly dubious; it zaps the transformations in
+             * place.  This seems inconsistent with the general treatment of the
+             * transformations elsewhere.
              */
-            png_ptr->transformations &= ~PNG_BACKGROUND;
-            png_ptr->transformations &= ~PNG_GAMMA;
-            png_ptr->transformations |= PNG_STRIP_ALPHA;
-         }
+            png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
+         } /* color_type == PNG_COLOR_TYPE_PALETTE */
 
          /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
-         else
-         /* color_type != PNG_COLOR_TYPE_PALETTE */
+         else /* color_type != PNG_COLOR_TYPE_PALETTE */
          {
             png_fixed_point g = PNG_FP_1;
             png_fixed_point gs = PNG_FP_1;
@@ -1164,17 +1709,21 @@ png_init_read_transformations(png_structp png_ptr)
                png_ptr->background.red = png_ptr->background.green
                    = png_ptr->background.blue = png_ptr->background.gray;
             }
-         }
-      }
+         } /* color_type != PNG_COLOR_TYPE_PALETTE */
+      }/* png_ptr->transformations & PNG_BACKGROUND */
+
       else
       /* Transformation does not include PNG_BACKGROUND */
 #endif /* PNG_READ_BACKGROUND_SUPPORTED */
-      if (color_type == PNG_COLOR_TYPE_PALETTE)
+      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
          png_colorp palette = png_ptr->palette;
          int num_palette = png_ptr->num_palette;
          int i;
 
+         /*NOTE: there are other transformations that should probably be in here
+          * too.
+          */
          for (i = 0; i < num_palette; i++)
          {
             palette[i].red = png_ptr->gamma_table[palette[i].red];
@@ -1184,16 +1733,17 @@ png_init_read_transformations(png_structp png_ptr)
 
          /* Done the gamma correction. */
          png_ptr->transformations &= ~PNG_GAMMA;
-      }
+      } /* color_type == PALETTE && !PNG_BACKGROUND transformation */
    }
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
    else
 #endif
 #endif /* PNG_READ_GAMMA_SUPPORTED */
+
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
-   /* No GAMMA transformation */
-   if ((png_ptr->transformations & PNG_BACKGROUND) &&
-       (color_type == PNG_COLOR_TYPE_PALETTE))
+   /* No GAMMA transformation (see the hanging else 4 lines above) */
+   if ((png_ptr->transformations & PNG_COMPOSE) &&
+       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
    {
       int i;
       int istop = (int)png_ptr->num_trans;
@@ -1225,15 +1775,13 @@ png_init_read_transformations(png_structp png_ptr)
          }
       }
 
-      /* Handled alpha, still need to strip the channel. */
-      png_ptr->transformations &= ~PNG_BACKGROUND;
-      png_ptr->transformations |= PNG_STRIP_ALPHA;
+      png_ptr->transformations &= ~PNG_COMPOSE;
    }
 #endif /* PNG_READ_BACKGROUND_SUPPORTED */
 
 #ifdef PNG_READ_SHIFT_SUPPORTED
    if ((png_ptr->transformations & PNG_SHIFT) &&
-       (color_type == PNG_COLOR_TYPE_PALETTE))
+       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
    {
       png_uint_16 i;
       png_uint_16 istop = png_ptr->num_palette;
@@ -1258,12 +1806,6 @@ png_init_read_transformations(png_structp png_ptr)
       }
    }
 #endif  /* PNG_READ_SHIFT_SUPPORTED */
- }
-#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
- && !defined(PNG_READ_BACKGROUND_SUPPORTED)
-   if (png_ptr)
-      return;
-#endif
 }
 
 /* Modify the info structure to reflect the transformations.  The
@@ -1280,8 +1822,11 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
    {
       if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
-         if (png_ptr->num_trans &&
-             (png_ptr->transformations & PNG_EXPAND_tRNS))
+         /* This check must match what actually happens in
+          * png_do_expand_palette; if it ever checks the tRNS chunk to see if
+          * it is all opaque we must do the same (at present it does not.)
+          */
+         if (png_ptr->num_trans > 0)
             info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
 
          else
@@ -1305,44 +1850,61 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
    }
 #endif
 
-#ifdef PNG_READ_EXPAND_16_SUPPORTED
-   if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 &&
-      info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
-   {
-      info_ptr->bit_depth = 16;
-   }
-#endif
-
-#ifdef PNG_READ_BACKGROUND_SUPPORTED
-   if (png_ptr->transformations & PNG_BACKGROUND)
-   {
-      info_ptr->color_type = (png_byte)(info_ptr->color_type &
-          ~PNG_COLOR_MASK_ALPHA);
-      info_ptr->num_trans = 0;
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)
+   /* The following is almost certainly wrong unless the background value is in
+    * the screen space!
+    */
+   if (png_ptr->transformations & PNG_COMPOSE)
       info_ptr->background = png_ptr->background;
-   }
 #endif
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
-   if (png_ptr->transformations & PNG_GAMMA)
-   {
-      info_ptr->gamma = png_ptr->gamma;
-   }
+   /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),
+    * however it seems that the code in png_init_read_transformations, which has
+    * been called before this from png_read_update_info->png_read_start_row
+    * sometimes does the gamma transform and cancels the flag.
+    */
+   info_ptr->gamma = png_ptr->gamma;
 #endif
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-#ifdef PNG_READ_16BIT_SUPPORTED
-   if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
-      info_ptr->bit_depth = 8;
-#else
-   /* Force chopping 16-bit input down to 8 */
    if (info_ptr->bit_depth == 16)
    {
-      png_ptr->transformations |=PNG_16_TO_8;
-      info_ptr->bit_depth = 8;
+#  ifdef PNG_READ_16BIT_SUPPORTED
+#     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+         if (png_ptr->transformations & PNG_SCALE_16_TO_8)
+            info_ptr->bit_depth = 8;
+#     endif
+
+#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+         if (png_ptr->transformations & PNG_16_TO_8)
+            info_ptr->bit_depth = 8;
+#     endif
+
+#  else
+      /* No 16 bit support: force chopping 16-bit input down to 8, in this case
+       * the app program can chose if both APIs are available by setting the
+       * correct scaling to use.
+       */
+#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+         /* For compatibility with previous versions use the strip method by
+          * default.  This code works because if PNG_SCALE_16_TO_8 is already
+          * set the code below will do that in preference to the chop.
+          */
+         png_ptr->transformations |= PNG_16_TO_8;
+         info_ptr->bit_depth = 8;
+#     else
+
+#        if PNG_READ_SCALE_16_TO_8_SUPPORTED
+            png_ptr->transformations |= PNG_SCALE_16_TO_8;
+            info_ptr->bit_depth = 8;
+#        else
+
+            CONFIGURATION ERROR: you must enable at least one 16 to 8 method
+#        endif
+#    endif
+#endif /* !READ_16BIT_SUPPORTED */
    }
-#endif
-#endif
 
 #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
    if (png_ptr->transformations & PNG_GRAY_TO_RGB)
@@ -1366,6 +1928,14 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
    }
 #endif
 
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
+   if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 &&
+      info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+   {
+      info_ptr->bit_depth = 16;
+   }
+#endif
+
 #ifdef PNG_READ_PACK_SUPPORTED
    if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
       info_ptr->bit_depth = 8;
@@ -1382,7 +1952,10 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
 
 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
    if (png_ptr->transformations & PNG_STRIP_ALPHA)
+   {
       info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+      info_ptr->num_trans = 0;
+   }
 #endif
 
    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
@@ -1418,6 +1991,14 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
 
    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
 
+   /* Adding in 1.5.4: cache the above value in png_struct so that we can later
+    * check in png_rowbytes that the user buffer won't get overwritten.  Note
+    * that the field is not always set - if png_read_update_info isn't called
+    * the application has to either not do any transforms or get the calculation
+    * right itself.
+    */
+   png_ptr->info_rowbytes = info_ptr->rowbytes;
+
 #ifndef PNG_READ_EXPAND_SUPPORTED
    if (png_ptr)
       return;
@@ -1435,29 +2016,27 @@ png_do_read_transformations(png_structp png_ptr)
 
    if (png_ptr->row_buf == NULL)
    {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-      char msg[50];
-
-      png_snprintf2(msg, 50,
-          "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number,
-          png_ptr->pass);
-      png_error(png_ptr, msg);
-#else
+      /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this
+       * error is incredibly rare and incredibly easy to debug without this
+       * information.
+       */
       png_error(png_ptr, "NULL row buffer");
-#endif
    }
-#ifdef PNG_WARN_UNINITIALIZED_ROW
-   if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
-      /* Application has failed to call either png_read_start_image()
-       * or png_read_update_info() after setting transforms that expand
-       * pixels.  This check added to libpng-1.2.19
+
+   /* The following is debugging; prior to 1.5.4 the code was never compiled in;
+    * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro
+    * PNG_WARN_UNINITIALIZED_ROW removed.  In 1.5 the new flag is set only for
+    * selected new APIs to ensure that there is no API change.
+    */
+   if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&
+      !(png_ptr->flags & PNG_FLAG_ROW_INIT))
+   {
+      /* Application has failed to call either png_read_start_image() or
+       * png_read_update_info() after setting transforms that expand pixels.
+       * This check added to libpng-1.2.19 (but not enabled until 1.5.4).
        */
-#if (PNG_WARN_UNINITIALIZED_ROW==1)
       png_error(png_ptr, "Uninitialized row");
-#else
-      png_warning(png_ptr, "Uninitialized row");
-#endif
-#endif
+   }
 
 #ifdef PNG_READ_EXPAND_SUPPORTED
    if (png_ptr->transformations & PNG_EXPAND)
@@ -1482,16 +2061,13 @@ png_do_read_transformations(png_structp png_ptr)
    }
 #endif
 
-   /* Delay the 'expand 16' step until later for efficiency, so that the
-    * intermediate steps work with 8 bit data.
-    */
-
 #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
    if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
+      !(png_ptr->transformations & PNG_COMPOSE) &&
       (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
       png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
       png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1,
-         0/*!at_start, because SWAP_ALPHA happens later*/);
+         0 /* at_start == false, because SWAP_ALPHA happens later */);
 #endif
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
@@ -1555,36 +2131,49 @@ png_do_read_transformations(png_structp png_ptr)
       png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
 
-#ifdef PNG_READ_BACKGROUND_SUPPORTED
-   if ((png_ptr->transformations & PNG_BACKGROUND) &&
-       ((png_ptr->num_trans != 0) ||
-       (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
-      png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
-          &(png_ptr->trans_color), &(png_ptr->background)
-#ifdef PNG_READ_GAMMA_SUPPORTED
-          , &(png_ptr->background_1),
-          png_ptr->gamma_table, png_ptr->gamma_from_1,
-          png_ptr->gamma_to_1, png_ptr->gamma_16_table,
-          png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
-          png_ptr->gamma_shift
-#endif
-          );
+#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
+   (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+   if (png_ptr->transformations & PNG_COMPOSE)
+      png_do_compose(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr);
 #endif
 
 #ifdef PNG_READ_GAMMA_SUPPORTED
    if ((png_ptr->transformations & PNG_GAMMA) &&
-#ifdef PNG_READ_BACKGROUND_SUPPORTED
-       !((png_ptr->transformations & PNG_BACKGROUND) &&
+#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
+   (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+       !((png_ptr->transformations & PNG_COMPOSE) &&
        ((png_ptr->num_trans != 0) ||
        (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
 #endif
        (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
-      png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
-          png_ptr->gamma_table, png_ptr->gamma_16_table,
-          png_ptr->gamma_shift);
+      png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr);
+#endif
+
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+   if ((png_ptr->transformations & PNG_STRIP_ALPHA) &&
+      (png_ptr->transformations & PNG_COMPOSE) &&
+      (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
+      png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+      png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1,
+         0 /* at_start == false, because SWAP_ALPHA happens later */);
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+   if ((png_ptr->transformations & PNG_ENCODE_ALPHA) &&
+      (png_ptr->row_info.color_type & PNG_COLOR_MASK_ALPHA))
+      png_do_encode_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr);
 #endif
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+   if (png_ptr->transformations & PNG_SCALE_16_TO_8)
+      png_do_scale_16_to_8(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+   /* There is no harm in doing both of these because only one has any effect,
+    * by putting the 'scale' option first if the app asks for scale (either by
+    * calling the API or in a TRANSFORM flag) this is what happens.
+    */
    if (png_ptr->transformations & PNG_16_TO_8)
       png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
@@ -1610,6 +2199,13 @@ png_do_read_transformations(png_structp png_ptr)
       png_do_expand_16(&png_ptr->row_info, png_ptr->row_buf + 1);
 #endif
 
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
+   /*NOTE: moved here in 1.5.4 (from much later in this list.) */
+   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+       (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
+      png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
 #ifdef PNG_READ_INVERT_SUPPORTED
    if (png_ptr->transformations & PNG_INVERT_MONO)
       png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
@@ -1636,16 +2232,6 @@ png_do_read_transformations(png_structp png_ptr)
       png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
 #endif
 
-#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
-   /*NOTE: this must be in the wrong place - what happens if BGR is set too?
-    * Need pngvalid to test this combo.
-    */
-   /* If gray -> RGB, do so now only if we did not do so above */
-   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
-       (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
-      png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
-#endif
-
 #ifdef PNG_READ_FILLER_SUPPORTED
    if (png_ptr->transformations & PNG_FILLER)
       png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
@@ -1697,7 +2283,6 @@ png_do_read_transformations(png_structp png_ptr)
           png_ptr->row_info.width);
    }
 #endif
-
 }
 
 #ifdef PNG_READ_PACK_SUPPORTED
@@ -1919,54 +2504,86 @@ png_do_unshift(png_row_infop row_info, png_bytep row,
 }
 #endif
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-/* Chop rows of bit depth 16 down to 8 */
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+/* Scale rows of bit depth 16 down to 8 accurately */
 void /* PRIVATE */
-png_do_chop(png_row_infop row_info, png_bytep row)
+png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
 {
-   png_debug(1, "in png_do_chop");
+   png_debug(1, "in png_do_scale_16_to_8");
 
    if (row_info->bit_depth == 16)
    {
-      png_bytep sp = row;
-      png_bytep dp = row;
-      png_uint_32 i;
-      png_uint_32 istop = row_info->width * row_info->channels;
+      png_bytep sp = row; /* source */
+      png_bytep dp = row; /* destinaton */
+      png_bytep ep = sp + row_info->rowbytes; /* end+1 */
 
-      for (i = 0; i<istop; i++, sp += 2, dp++)
+      while (sp < ep)
       {
-#ifdef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
-      /* This does a more accurate scaling of the 16-bit color
-       * value, rather than a simple low-byte truncation.
-       *
-       * What the ideal calculation should be:
-       *   *dp = (((((png_uint_32)(*sp) << 8) |
-       *          (png_uint_32)(*(sp + 1))) * 255 + 127)
-       *          / (png_uint_32)65535L;
-       *
-       * GRR: no, I think this is what it really should be:
-       *   *dp = (((((png_uint_32)(*sp) << 8) |
-       *           (png_uint_32)(*(sp + 1))) + 128L)
-       *           / (png_uint_32)257L;
-       *
-       * GRR: here's the exact calculation with shifts:
-       *   temp = (((png_uint_32)(*sp) << 8) |
-       *           (png_uint_32)(*(sp + 1))) + 128L;
-       *   *dp = (temp - (temp >> 8)) >> 8;
-       *
-       * Approximate calculation with shift/add instead of multiply/divide:
-       *   *dp = ((((png_uint_32)(*sp) << 8) |
-       *          (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
-       *
-       * What we actually do to avoid extra shifting and conversion:
-       */
+         /* The input is an array of 16 bit components, these must be scaled to
+          * 8 bits each.  For a 16 bit value V the required value (from the PNG
+          * specification) is:
+          *
+          *    (V * 255) / 65535
+          *
+          * This reduces to round(V / 257), or floor((V + 128.5)/257)
+          *
+          * Represent V as the two byte value vhi.vlo.  Make a guess that the
+          * result is the top byte of V, vhi, then the correction to this value
+          * is:
+          *
+          *    error = floor(((V-vhi.vhi) + 128.5) / 257)
+          *          = floor(((vlo-vhi) + 128.5) / 257)
+          *
+          * This can be approximated using integer arithmetic (and a signed
+          * shift):
+          *
+          *    error = (vlo-vhi+128) >> 8;
+          *
+          * The approximate differs from the exact answer only when (vlo-vhi) is
+          * 128; it then gives a correction of +1 when the exact correction is
+          * 0.  This gives 128 errors.  The exact answer (correct for all 16 bit
+          * input values) is:
+          *
+          *    error = (vlo-vhi+128)*65535 >> 24;
+          *
+          * An alternative arithmetic calculation which also gives no errors is:
+          *
+          *    (V * 255 + 32895) >> 16
+          */
 
-         *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
-#else
-       /* Simply discard the low order byte */
-         *dp = *sp;
+         png_int_32 tmp = *sp++; /* must be signed! */
+         tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;
+         *dp++ = (png_byte)tmp;
+      }
+
+      row_info->bit_depth = 8;
+      row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+      row_info->rowbytes = row_info->width * row_info->channels;
+   }
+}
 #endif
+
+#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
+void /* PRIVATE */
+/* Simply discard the low byte.  This was the default behavior prior
+ * to libpng-1.5.4.
+ */
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+   png_debug(1, "in png_do_chop");
+
+   if (row_info->bit_depth == 16)
+   {
+      png_bytep sp = row; /* source */
+      png_bytep dp = row; /* destinaton */
+      png_bytep ep = sp + row_info->rowbytes; /* end+1 */
+
+      while (sp < ep)
+      {
+         *dp++ = *sp;
+         sp += 2; /* skip low byte */
       }
+
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
       row_info->rowbytes = row_info->width * row_info->channels;
@@ -2721,11 +3338,13 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
    return rgb_error;
 }
 #endif
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
+#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
 /* Build a grayscale palette.  Palette is assumed to be 1 << bit_depth
  * large of png_color.  This lets grayscale images be treated as
  * paletted.  Most useful for gamma correction and simplification
- * of code.
+ * of code.  This API is not used internally.
  */
 void PNGAPI
 png_build_grayscale_palette(int bit_depth, png_colorp palette)
@@ -2775,34 +3394,36 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette)
       palette[i].blue = (png_byte)v;
    }
 }
+#endif
 
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 #ifdef PNG_READ_BACKGROUND_SUPPORTED
 /* Replace any alpha or transparency with the supplied background color.
  * "background" is already in the screen gamma, while "background_1" is
  * at a gamma of 1.0.  Paletted files have already been taken care of.
  */
 void /* PRIVATE */
-png_do_background(png_row_infop row_info, png_bytep row,
-    png_const_color_16p trans_color, png_const_color_16p background
+png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
+{
 #ifdef PNG_READ_GAMMA_SUPPORTED
-    , png_const_color_16p background_1, png_const_bytep gamma_table,
-    png_const_bytep gamma_from_1, png_const_bytep gamma_to_1,
-    png_const_uint_16pp gamma_16, png_const_uint_16pp gamma_16_from_1,
-    png_const_uint_16pp gamma_16_to_1, int gamma_shift
+   png_const_bytep gamma_table = png_ptr->gamma_table;
+   png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;
+   png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;
+   png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;
+   png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;
+   png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;
+   int gamma_shift = png_ptr->gamma_shift;
 #endif
-    )
-{
-   png_bytep sp, dp;
+
+   png_bytep sp;
    png_uint_32 i;
    png_uint_32 row_width = row_info->width;
+   int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
    int shift;
 
-   png_debug(1, "in png_do_background");
+   png_debug(1, "in png_do_compose");
 
-   if (background != NULL &&
-      (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
-      (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color)))
    {
       switch (row_info->color_type)
       {
@@ -2817,10 +3438,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                   for (i = 0; i < row_width; i++)
                   {
                      if ((png_uint_16)((*sp >> shift) & 0x01)
-                        == trans_color->gray)
+                        == png_ptr->trans_color.gray)
                      {
                         *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
-                        *sp |= (png_byte)(background->gray << shift);
+                        *sp |= (png_byte)(png_ptr->background.gray << shift);
                      }
 
                      if (!shift)
@@ -2845,10 +3466,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x03)
-                            == trans_color->gray)
+                            == png_ptr->trans_color.gray)
                         {
                            *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
-                           *sp |= (png_byte)(background->gray << shift);
+                           *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
                         else
@@ -2879,10 +3500,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x03)
-                            == trans_color->gray)
+                            == png_ptr->trans_color.gray)
                         {
                            *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
-                           *sp |= (png_byte)(background->gray << shift);
+                           *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
                         if (!shift)
@@ -2908,10 +3529,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x0f)
-                            == trans_color->gray)
+                            == png_ptr->trans_color.gray)
                         {
                            *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
-                           *sp |= (png_byte)(background->gray << shift);
+                           *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
                         else
@@ -2942,10 +3563,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      for (i = 0; i < row_width; i++)
                      {
                         if ((png_uint_16)((*sp >> shift) & 0x0f)
-                            == trans_color->gray)
+                            == png_ptr->trans_color.gray)
                         {
                            *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
-                           *sp |= (png_byte)(background->gray << shift);
+                           *sp |= (png_byte)(png_ptr->background.gray << shift);
                         }
 
                         if (!shift)
@@ -2969,8 +3590,8 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      sp = row;
                      for (i = 0; i < row_width; i++, sp++)
                      {
-                        if (*sp == trans_color->gray)
-                           *sp = (png_byte)background->gray;
+                        if (*sp == png_ptr->trans_color.gray)
+                           *sp = (png_byte)png_ptr->background.gray;
 
                         else
                            *sp = gamma_table[*sp];
@@ -2982,8 +3603,8 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      sp = row;
                      for (i = 0; i < row_width; i++, sp++)
                      {
-                        if (*sp == trans_color->gray)
-                           *sp = (png_byte)background->gray;
+                        if (*sp == png_ptr->trans_color.gray)
+                           *sp = (png_byte)png_ptr->background.gray;
                      }
                   }
                   break;
@@ -3001,11 +3622,11 @@ png_do_background(png_row_infop row_info, png_bytep row,
 
                         v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
 
-                        if (v == trans_color->gray)
+                        if (v == png_ptr->trans_color.gray)
                         {
                            /* Background is already in screen gamma */
-                           *sp = (png_byte)((background->gray >> 8) & 0xff);
-                           *(sp + 1) = (png_byte)(background->gray & 0xff);
+                           *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                           *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                         }
 
                         else
@@ -3026,10 +3647,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
 
                         v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
 
-                        if (v == trans_color->gray)
+                        if (v == png_ptr->trans_color.gray)
                         {
-                           *sp = (png_byte)((background->gray >> 8) & 0xff);
-                           *(sp + 1) = (png_byte)(background->gray & 0xff);
+                           *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                           *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                         }
                      }
                   }
@@ -3052,13 +3673,13 @@ png_do_background(png_row_infop row_info, png_bytep row,
                   sp = row;
                   for (i = 0; i < row_width; i++, sp += 3)
                   {
-                     if (*sp == trans_color->red &&
-                         *(sp + 1) == trans_color->green &&
-                         *(sp + 2) == trans_color->blue)
+                     if (*sp == png_ptr->trans_color.red &&
+                         *(sp + 1) == png_ptr->trans_color.green &&
+                         *(sp + 2) == png_ptr->trans_color.blue)
                      {
-                        *sp = (png_byte)background->red;
-                        *(sp + 1) = (png_byte)background->green;
-                        *(sp + 2) = (png_byte)background->blue;
+                        *sp = (png_byte)png_ptr->background.red;
+                        *(sp + 1) = (png_byte)png_ptr->background.green;
+                        *(sp + 2) = (png_byte)png_ptr->background.blue;
                      }
 
                      else
@@ -3075,13 +3696,13 @@ png_do_background(png_row_infop row_info, png_bytep row,
                   sp = row;
                   for (i = 0; i < row_width; i++, sp += 3)
                   {
-                     if (*sp == trans_color->red &&
-                         *(sp + 1) == trans_color->green &&
-                         *(sp + 2) == trans_color->blue)
+                     if (*sp == png_ptr->trans_color.red &&
+                         *(sp + 1) == png_ptr->trans_color.green &&
+                         *(sp + 2) == png_ptr->trans_color.blue)
                      {
-                        *sp = (png_byte)background->red;
-                        *(sp + 1) = (png_byte)background->green;
-                        *(sp + 2) = (png_byte)background->blue;
+                        *sp = (png_byte)png_ptr->background.red;
+                        *(sp + 1) = (png_byte)png_ptr->background.green;
+                        *(sp + 2) = (png_byte)png_ptr->background.blue;
                      }
                   }
                }
@@ -3102,16 +3723,17 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
                          + *(sp + 5));
 
-                     if (r == trans_color->red && g == trans_color->green &&
-                         b == trans_color->blue)
+                     if (r == png_ptr->trans_color.red &&
+                         g == png_ptr->trans_color.green &&
+                         b == png_ptr->trans_color.blue)
                      {
                         /* Background is already in screen gamma */
-                        *sp = (png_byte)((background->red >> 8) & 0xff);
-                        *(sp + 1) = (png_byte)(background->red & 0xff);
-                        *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(background->green & 0xff);
-                        *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
-                        *(sp + 5) = (png_byte)(background->blue & 0xff);
+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
                      else
@@ -3145,15 +3767,16 @@ png_do_background(png_row_infop row_info, png_bytep row,
                      png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
                          + *(sp + 5));
 
-                     if (r == trans_color->red && g == trans_color->green &&
-                         b == trans_color->blue)
+                     if (r == png_ptr->trans_color.red &&
+                         g == png_ptr->trans_color.green &&
+                         b == png_ptr->trans_color.blue)
                      {
-                        *sp = (png_byte)((background->red >> 8) & 0xff);
-                        *(sp + 1) = (png_byte)(background->red & 0xff);
-                        *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
-                        *(sp + 3) = (png_byte)(background->green & 0xff);
-                        *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
-                        *(sp + 5) = (png_byte)(background->blue & 0xff);
+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
                   }
                }
@@ -3170,18 +3793,17 @@ png_do_background(png_row_infop row_info, png_bytep row,
                    gamma_table != NULL)
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 2, dp++)
+                  for (i = 0; i < row_width; i++, sp += 2)
                   {
                      png_uint_16 a = *(sp + 1);
 
                      if (a == 0xff)
-                        *dp = gamma_table[*sp];
+                        *sp = gamma_table[*sp];
 
                      else if (a == 0)
                      {
                         /* Background is already in screen gamma */
-                        *dp = (png_byte)background->gray;
+                        *sp = (png_byte)png_ptr->background.gray;
                      }
 
                      else
@@ -3189,8 +3811,10 @@ png_do_background(png_row_infop row_info, png_bytep row,
                         png_byte v, w;
 
                         v = gamma_to_1[*sp];
-                        png_composite(w, v, a, background_1->gray);
-                        *dp = gamma_from_1[w];
+                        png_composite(w, v, a, png_ptr->background_1.gray);
+                        if (!optimize)
+                           w = gamma_from_1[w];
+                        *sp = w;
                      }
                   }
                }
@@ -3198,24 +3822,15 @@ png_do_background(png_row_infop row_info, png_bytep row,
 #endif
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 2, dp++)
+                  for (i = 0; i < row_width; i++, sp += 2)
                   {
                      png_byte a = *(sp + 1);
 
-                     if (a == 0xff)
-                        *dp = *sp;
-
-#ifdef PNG_READ_GAMMA_SUPPORTED
-                     else if (a == 0)
-                        *dp = (png_byte)background->gray;
-
-                     else
-                        png_composite(*dp, *sp, a, background_1->gray);
+                     if (a == 0)
+                        *sp = (png_byte)png_ptr->background.gray;
 
-#else
-                     *dp = (png_byte)background->gray;
-#endif
+                     else if (a < 0xff)
+                        png_composite(*sp, *sp, a, png_ptr->background_1.gray);
                   }
                }
             }
@@ -3226,8 +3841,7 @@ png_do_background(png_row_infop row_info, png_bytep row,
                    gamma_16_to_1 != NULL)
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+                  for (i = 0; i < row_width; i++, sp += 4)
                   {
                      png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
                          + *(sp + 3));
@@ -3237,69 +3851,56 @@ png_do_background(png_row_infop row_info, png_bytep row,
                         png_uint_16 v;
 
                         v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
-                        *dp = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(v & 0xff);
+                        *sp = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(v & 0xff);
                      }
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
                      else if (a == 0)
-#else
-                     else
-#endif
                      {
                         /* Background is already in screen gamma */
-                        *dp = (png_byte)((background->gray >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(background->gray & 0xff);
+                        *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                      }
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
                      else
                      {
                         png_uint_16 g, v, w;
 
                         g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
-                        png_composite_16(v, g, a, background_1->gray);
-                        w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
-                        *dp = (png_byte)((w >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(w & 0xff);
+                        png_composite_16(v, g, a, png_ptr->background_1.gray);
+                        if (optimize)
+                           w = v;
+                        else
+                           w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+                        *sp = (png_byte)((w >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(w & 0xff);
                      }
-#endif
                   }
                }
                else
 #endif
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+                  for (i = 0; i < row_width; i++, sp += 4)
                   {
                      png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
                          + *(sp + 3));
 
-                     if (a == (png_uint_16)0xffff)
-                        png_memcpy(dp, sp, 2);
-
-#ifdef PNG_READ_GAMMA_SUPPORTED
-                     else if (a == 0)
-#else
-                     else
-#endif
+                     if (a == 0)
                      {
-                        *dp = (png_byte)((background->gray >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(background->gray & 0xff);
+                        *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
                      }
 
-#ifdef PNG_READ_GAMMA_SUPPORTED
-                     else
+                     else if (a < 0xffff)
                      {
                         png_uint_16 g, v;
 
                         g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
-                        png_composite_16(v, g, a, background_1->gray);
-                        *dp = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(v & 0xff);
+                        png_composite_16(v, g, a, png_ptr->background_1.gray);
+                        *sp = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(v & 0xff);
                      }
-#endif
                   }
                }
             }
@@ -3315,24 +3916,23 @@ png_do_background(png_row_infop row_info, png_bytep row,
                    gamma_table != NULL)
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+                  for (i = 0; i < row_width; i++, sp += 4)
                   {
                      png_byte a = *(sp + 3);
 
                      if (a == 0xff)
                      {
-                        *dp = gamma_table[*sp];
-                        *(dp + 1) = gamma_table[*(sp + 1)];
-                        *(dp + 2) = gamma_table[*(sp + 2)];
+                        *sp = gamma_table[*sp];
+                        *(sp + 1) = gamma_table[*(sp + 1)];
+                        *(sp + 2) = gamma_table[*(sp + 2)];
                      }
 
                      else if (a == 0)
                      {
                         /* Background is already in screen gamma */
-                        *dp = (png_byte)background->red;
-                        *(dp + 1) = (png_byte)background->green;
-                        *(dp + 2) = (png_byte)background->blue;
+                        *sp = (png_byte)png_ptr->background.red;
+                        *(sp + 1) = (png_byte)png_ptr->background.green;
+                        *(sp + 2) = (png_byte)png_ptr->background.blue;
                      }
 
                      else
@@ -3340,16 +3940,19 @@ png_do_background(png_row_infop row_info, png_bytep row,
                         png_byte v, w;
 
                         v = gamma_to_1[*sp];
-                        png_composite(w, v, a, background_1->red);
-                        *dp = gamma_from_1[w];
+                        png_composite(w, v, a, png_ptr->background_1.red);
+                        if (!optimize) w = gamma_from_1[w];
+                        *sp = w;
 
                         v = gamma_to_1[*(sp + 1)];
-                        png_composite(w, v, a, background_1->green);
-                        *(dp + 1) = gamma_from_1[w];
+                        png_composite(w, v, a, png_ptr->background_1.green);
+                        if (!optimize) w = gamma_from_1[w];
+                        *(sp + 1) = w;
 
                         v = gamma_to_1[*(sp + 2)];
-                        png_composite(w, v, a, background_1->blue);
-                        *(dp + 2) = gamma_from_1[w];
+                        png_composite(w, v, a, png_ptr->background_1.blue);
+                        if (!optimize) w = gamma_from_1[w];
+                        *(sp + 2) = w;
                      }
                   }
                }
@@ -3357,34 +3960,26 @@ png_do_background(png_row_infop row_info, png_bytep row,
 #endif
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+                  for (i = 0; i < row_width; i++, sp += 4)
                   {
                      png_byte a = *(sp + 3);
 
-                     if (a == 0xff)
-                     {
-                        *dp = *sp;
-                        *(dp + 1) = *(sp + 1);
-                        *(dp + 2) = *(sp + 2);
-                     }
-
-                     else if (a == 0)
+                     if (a == 0)
                      {
-                        *dp = (png_byte)background->red;
-                        *(dp + 1) = (png_byte)background->green;
-                        *(dp + 2) = (png_byte)background->blue;
+                        *sp = (png_byte)png_ptr->background.red;
+                        *(sp + 1) = (png_byte)png_ptr->background.green;
+                        *(sp + 2) = (png_byte)png_ptr->background.blue;
                      }
 
-                     else
+                     else if (a < 0xff)
                      {
-                        png_composite(*dp, *sp, a, background->red);
+                        png_composite(*sp, *sp, a, png_ptr->background.red);
 
-                        png_composite(*(dp + 1), *(sp + 1), a,
-                            background->green);
+                        png_composite(*(sp + 1), *(sp + 1), a,
+                            png_ptr->background.green);
 
-                        png_composite(*(dp + 2), *(sp + 2), a,
-                            background->blue);
+                        png_composite(*(sp + 2), *(sp + 2), a,
+                            png_ptr->background.blue);
                      }
                   }
                }
@@ -3396,8 +3991,7 @@ png_do_background(png_row_infop row_info, png_bytep row,
                    gamma_16_to_1 != NULL)
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+                  for (i = 0; i < row_width; i++, sp += 8)
                   {
                      png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
                          << 8) + (png_uint_16)(*(sp + 7)));
@@ -3407,53 +4001,55 @@ png_do_background(png_row_infop row_info, png_bytep row,
                         png_uint_16 v;
 
                         v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
-                        *dp = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(v & 0xff);
+                        *sp = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(v & 0xff);
 
                         v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
-                        *(dp + 2) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(v & 0xff);
+                        *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(v & 0xff);
 
                         v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
-                        *(dp + 4) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(v & 0xff);
+                        *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(v & 0xff);
                      }
 
                      else if (a == 0)
                      {
                         /* Background is already in screen gamma */
-                        *dp = (png_byte)((background->red >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(background->red & 0xff);
-                        *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(background->green & 0xff);
-                        *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(background->blue & 0xff);
+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
                      else
                      {
-                        png_uint_16 v, w, x;
+                        png_uint_16 v, w;
 
                         v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
-                        png_composite_16(w, v, a, background_1->red);
-
-                        x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
-                        *dp = (png_byte)((x >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(x & 0xff);
+                        png_composite_16(w, v, a, png_ptr->background_1.red);
+                        if (!optimize)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+                        *sp = (png_byte)((w >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(w & 0xff);
 
                         v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
-                        png_composite_16(w, v, a, background_1->green);
+                        png_composite_16(w, v, a, png_ptr->background_1.green);
+                        if (!optimize)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
 
-                        x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
-                        *(dp + 2) = (png_byte)((x >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(x & 0xff);
+                        *(sp + 2) = (png_byte)((w >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(w & 0xff);
 
                         v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
-                        png_composite_16(w, v, a, background_1->blue);
+                        png_composite_16(w, v, a, png_ptr->background_1.blue);
+                        if (!optimize)
+                           w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
 
-                        x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
-                        *(dp + 4) = (png_byte)((x >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(x & 0xff);
+                        *(sp + 4) = (png_byte)((w >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(w & 0xff);
                      }
                   }
                }
@@ -3462,28 +4058,22 @@ png_do_background(png_row_infop row_info, png_bytep row,
 #endif
                {
                   sp = row;
-                  dp = row;
-                  for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+                  for (i = 0; i < row_width; i++, sp += 8)
                   {
                      png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
                          << 8) + (png_uint_16)(*(sp + 7)));
 
-                     if (a == (png_uint_16)0xffff)
-                     {
-                        png_memcpy(dp, sp, 6);
-                     }
-
-                     else if (a == 0)
+                     if (a == 0)
                      {
-                        *dp = (png_byte)((background->red >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(background->red & 0xff);
-                        *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(background->green & 0xff);
-                        *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(background->blue & 0xff);
+                        *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
+                        *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
+                        *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
                      }
 
-                     else
+                     else if (a < 0xffff)
                      {
                         png_uint_16 v;
 
@@ -3493,17 +4083,17 @@ png_do_background(png_row_infop row_info, png_bytep row,
                         png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
                             + *(sp + 5));
 
-                        png_composite_16(v, r, a, background->red);
-                        *dp = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 1) = (png_byte)(v & 0xff);
+                        png_composite_16(v, r, a, png_ptr->background.red);
+                        *sp = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 1) = (png_byte)(v & 0xff);
 
-                        png_composite_16(v, g, a, background->green);
-                        *(dp + 2) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 3) = (png_byte)(v & 0xff);
+                        png_composite_16(v, g, a, png_ptr->background.green);
+                        *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 3) = (png_byte)(v & 0xff);
 
-                        png_composite_16(v, b, a, background->blue);
-                        *(dp + 4) = (png_byte)((v >> 8) & 0xff);
-                        *(dp + 5) = (png_byte)(v & 0xff);
+                        png_composite_16(v, b, a, png_ptr->background.blue);
+                        *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+                        *(sp + 5) = (png_byte)(v & 0xff);
                      }
                   }
                }
@@ -3514,16 +4104,6 @@ png_do_background(png_row_infop row_info, png_bytep row,
          default:
             break;
       }
-
-      if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
-      {
-         row_info->color_type = (png_byte)(row_info->color_type &
-             ~PNG_COLOR_MASK_ALPHA);
-         row_info->channels--;
-         row_info->pixel_depth = (png_byte)(row_info->channels *
-             row_info->bit_depth);
-         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
-      }
    }
 }
 #endif
@@ -3536,10 +4116,12 @@ png_do_background(png_row_infop row_info, png_bytep row,
  * build_gamma_table().
  */
 void /* PRIVATE */
-png_do_gamma(png_row_infop row_info, png_bytep row,
-    png_const_bytep gamma_table, png_const_uint_16pp gamma_16_table,
-    int gamma_shift)
+png_do_gamma(png_row_infop row_info, png_bytep row, png_structp png_ptr)
 {
+   png_const_bytep gamma_table = png_ptr->gamma_table;
+   png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;
+   int gamma_shift = png_ptr->gamma_shift;
+
    png_bytep sp;
    png_uint_32 i;
    png_uint_32 row_width=row_info->width;
@@ -3729,6 +4311,73 @@ png_do_gamma(png_row_infop row_info, png_bytep row,
 }
 #endif
 
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+/* Encode the alpha channel to the output gamma (the input channel is always
+ * linear.)  Called only with color types that have an alpha channel.  Needs the
+ * from_1 tables.
+ */
+void /* PRIVATE */
+png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structp png_ptr)
+{
+   png_uint_32 row_width = row_info->width;
+
+   png_debug(1, "in png_do_encode_alpha");
+
+   if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+   {
+      if (row_info->bit_depth == 8)
+      {
+         PNG_CONST png_bytep table = png_ptr->gamma_from_1;
+
+         if (table != NULL)
+         {
+            PNG_CONST int step =
+               (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;
+
+            /* The alpha channel is the last component: */
+            row += step - 1;
+
+            for (; row_width > 0; --row_width, row += step)
+               *row = table[*row];
+
+            return;
+         }
+      }
+
+      else if (row_info->bit_depth == 16)
+      {
+         PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1;
+         PNG_CONST int gamma_shift = png_ptr->gamma_shift;
+
+         if (table != NULL)
+         {
+            PNG_CONST int step =
+               (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;
+
+            /* The alpha channel is the last component: */
+            row += step - 2;
+
+            for (; row_width > 0; --row_width, row += step)
+            {
+               png_uint_16 v;
+
+               v = table[*(row + 1) >> gamma_shift][*row];
+               *row = (png_byte)((v >> 8) & 0xff);
+               *(row + 1) = (png_byte)(v & 0xff);
+            }
+
+            return;
+         }
+      }
+   }
+
+   /* Only get to here if called with a weird row_info; no harm has been done,
+    * so just issue a warning.
+    */
+   png_warning(png_ptr, "png_do_encode_alpha: unexpected call");
+}
+#endif
+
 #ifdef PNG_READ_EXPAND_SUPPORTED
 /* Expands a palette row to an RGB or RGBA row depending
  * upon whether you supply trans and num_trans.
@@ -3834,7 +4483,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
       if (row_info->bit_depth == 8)
       {
          {
-            if (trans_alpha != NULL)
+            if (num_trans > 0)
             {
                sp = row + (png_size_t)row_width - 1;
                dp = row + (png_size_t)(row_width << 2) - 1;
@@ -3888,7 +4537,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row,
  */
 void /* PRIVATE */
 png_do_expand(png_row_infop row_info, png_bytep row,
-    png_const_color_16p trans_value)
+    png_const_color_16p trans_color)
 {
    int shift, value;
    png_bytep sp, dp;
@@ -3900,7 +4549,7 @@ png_do_expand(png_row_infop row_info, png_bytep row,
    {
       if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
       {
-         png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
+         png_uint_16 gray = (png_uint_16)(trans_color ? trans_color->gray : 0);
 
          if (row_info->bit_depth < 8)
          {
@@ -3992,7 +4641,7 @@ png_do_expand(png_row_infop row_info, png_bytep row,
             row_info->rowbytes = row_width;
          }
 
-         if (trans_value != NULL)
+         if (trans_color != NULL)
          {
             if (row_info->bit_depth == 8)
             {
@@ -4044,13 +4693,13 @@ png_do_expand(png_row_infop row_info, png_bytep row,
                row_width);
          }
       }
-      else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+      else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color)
       {
          if (row_info->bit_depth == 8)
          {
-            png_byte red = (png_byte)(trans_value->red & 0xff);
-            png_byte green = (png_byte)(trans_value->green & 0xff);
-            png_byte blue = (png_byte)(trans_value->blue & 0xff);
+            png_byte red = (png_byte)(trans_color->red & 0xff);
+            png_byte green = (png_byte)(trans_color->green & 0xff);
+            png_byte blue = (png_byte)(trans_color->blue & 0xff);
             sp = row + (png_size_t)row_info->rowbytes - 1;
             dp = row + (png_size_t)(row_width << 2) - 1;
             for (i = 0; i < row_width; i++)
@@ -4068,12 +4717,12 @@ png_do_expand(png_row_infop row_info, png_bytep row,
          }
          else if (row_info->bit_depth == 16)
          {
-            png_byte red_high = (png_byte)((trans_value->red >> 8) & 0xff);
-            png_byte green_high = (png_byte)((trans_value->green >> 8) & 0xff);
-            png_byte blue_high = (png_byte)((trans_value->blue >> 8) & 0xff);
-            png_byte red_low = (png_byte)(trans_value->red & 0xff);
-            png_byte green_low = (png_byte)(trans_value->green & 0xff);
-            png_byte blue_low = (png_byte)(trans_value->blue & 0xff);
+            png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);
+            png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);
+            png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);
+            png_byte red_low = (png_byte)(trans_color->red & 0xff);
+            png_byte green_low = (png_byte)(trans_color->green & 0xff);
+            png_byte blue_low = (png_byte)(trans_color->blue & 0xff);
             sp = row + row_info->rowbytes - 1;
             dp = row + (png_size_t)(row_width << 3) - 1;
             for (i = 0; i < row_width; i++)
@@ -4236,6 +4885,7 @@ png_do_quantize(png_row_infop row_info, png_bytep row,
    }
 }
 #endif /* PNG_READ_QUANTIZE_SUPPORTED */
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
 #ifdef PNG_MNG_FEATURES_SUPPORTED
 /* Undoes intrapixel differencing  */
index d4764317444f4ae85282c8e87d139329186971df..07e46e2feda5d682bda9b99a0d51b1235d504514 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -278,8 +278,7 @@ png_crc_error(png_structp png_ptr)
       return (0);
 }
 
-#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
-    defined(PNG_READ_iCCP_SUPPORTED)
+#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
 static png_size_t
 png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
     png_bytep output, png_size_t output_size)
@@ -370,41 +369,31 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
        * and the error message is dumped into the uncompressed
        * buffer if available.
        */
+#     ifdef PNG_WARNINGS_SUPPORTED
       {
-         PNG_CONST char *msg;
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         char umsg[52];
-#endif
+         png_const_charp msg;
+
          if (png_ptr->zstream.msg != 0)
             msg = png_ptr->zstream.msg;
 
-         else
+         else switch (ret)
          {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-            switch (ret)
-            {
-               case Z_BUF_ERROR:
-                  msg = "Buffer error in compressed datastream in %s chunk";
-                  break;
+            case Z_BUF_ERROR:
+               msg = "Buffer error in compressed datastream";
+               break;
 
-               case Z_DATA_ERROR:
-                  msg = "Data error in compressed datastream in %s chunk";
-                  break;
+            case Z_DATA_ERROR:
+               msg = "Data error in compressed datastream";
+               break;
 
-               default:
-                  msg = "Incomplete compressed datastream in %s chunk";
-                  break;
-            }
-
-            png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
-            msg = umsg;
-#else
-            msg = "Damaged compressed datastream in chunk other than IDAT";
-#endif
+            default:
+               msg = "Incomplete compressed datastream";
+               break;
          }
 
-         png_warning(png_ptr, msg);
+         png_chunk_warning(png_ptr, msg);
       }
+#     endif
 
       /* 0 means an error - notice that this code simply ignores
        * zero length compressed chunks as a result.
@@ -438,8 +427,8 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
       png_size_t expanded_size = png_inflate(png_ptr,
           (png_bytep)(png_ptr->chunkdata + prefix_size),
           chunklength - prefix_size,
-          0,            /*output*/
-          0);           /*output size*/
+          0,            /* output */
+          0);           /* output size */
 
       /* Now check the limits on this chunk - if the limit fails the
        * compressed data will be removed, the prefix will remain.
@@ -500,15 +489,9 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
 
    else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
    {
-#ifdef PNG_STDIO_SUPPORTED
-      char umsg[50];
-
-      png_snprintf(umsg, sizeof umsg,
-          "Unknown zTXt compression type %d", comp_type);
-      png_warning(png_ptr, umsg);
-#else
-      png_warning(png_ptr, "Unknown zTXt compression type");
-#endif
+      PNG_WARNING_PARAMETERS(p)
+      png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type);
+      png_formatted_warning(png_ptr, p, "Unknown zTXt compression type @1");
 
       /* The recovery is to simply drop the data. */
    }
@@ -536,7 +519,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
 
    *newlength = prefix_size;
 }
-#endif
+#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
 
 /* Read and check the IDHR chunk */
 void /* PRIVATE */
@@ -846,12 +829,10 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    {
       if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect gAMA value when sRGB is also present");
-
-#    ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
-#    endif
+         PNG_WARNING_PARAMETERS(p)
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma);
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect gAMA value @1 when sRGB is also present");
          return;
       }
    }
@@ -1020,21 +1001,52 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
           PNG_OUT_OF_RANGE(x_blue,  15000,  1000) ||
           PNG_OUT_OF_RANGE(y_blue,   6000,  1000))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect cHRM value when sRGB is also present");
-
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "wx=%d, wy=%d, rx=%d, ry=%d\n",
-             x_white, y_white, x_red, y_red);
-
-         fprintf(stderr, "gx=%d, gy=%d, bx=%d, by=%d\n",
-             x_green, y_green, x_blue, y_blue);
-#endif /* PNG_CONSOLE_IO_SUPPORTED */
+         PNG_WARNING_PARAMETERS(p)
+
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white);
+         png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white);
+         png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red);
+         png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red);
+         png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green);
+         png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green);
+         png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue);
+         png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue);
+
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) "
+             "when sRGB is also present");
       }
       return;
    }
 #endif /* PNG_READ_sRGB_SUPPORTED */
 
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+   /* Store the _white values as default coefficients for the rgb to gray
+    * operation if it is supported.
+    */
+   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
+   {
+      /* png_set_background has not been called, the coefficients must be in
+       * range for the following to work without overflow.
+       */
+      if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17))
+      {
+         /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray
+          * transformation are simply the normalized Y values for red, green and
+          * blue scaled by 32768.
+          */
+         png_uint_32 w = y_red + y_green + y_blue;
+
+         png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)(((png_uint_32)y_red *
+            32768)/w);
+         png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green
+            * 32768)/w);
+         png_ptr->rgb_to_gray_blue_coeff  = (png_uint_16)(((png_uint_32)y_blue *
+            32768)/w);
+      }
+   }
+#endif
+
    png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
       x_green, y_green, x_blue, y_blue);
 }
@@ -1096,11 +1108,13 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    {
       if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect gAMA value when sRGB is also present");
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "incorrect gamma=(%d/100000)\n", info_ptr->gamma);
-#endif
+         PNG_WARNING_PARAMETERS(p)
+
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed,
+            info_ptr->gamma);
+
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect gAMA value @1 when sRGB is also present");
       }
    }
 #endif /* PNG_READ_gAMA_SUPPORTED */
@@ -1240,23 +1254,15 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* And the following guarantees that profile_size == profile_length. */
    if (profile_size > profile_length)
    {
+      PNG_WARNING_PARAMETERS(p)
+
       png_free(png_ptr, png_ptr->chunkdata);
       png_ptr->chunkdata = NULL;
-#ifdef PNG_STDIO_SUPPORTED
-      {
-         char umsg[80];
-
-         png_snprintf2(umsg, 80,
-             "Ignoring iCCP chunk with declared size = %u "
-              "and actual length = %u",
-              (unsigned int) profile_size,
-              (unsigned int) profile_length);
-         png_warning(png_ptr, umsg);
-      }
-#else
-      png_warning(png_ptr,
-         "Ignoring iCCP chunk with uncompressed size mismatch");
-#endif
+
+      png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size);
+      png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length);
+      png_formatted_warning(png_ptr, p,
+         "Ignoring iCCP chunk with declared size = @1 and actual length = @2");
       return;
    }
 
@@ -1565,6 +1571,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
    png_size_t truelen;
    png_byte buf[6];
+   png_color_16 background;
 
    png_debug(1, "in png_handle_bKGD");
 
@@ -1621,7 +1628,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
     */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
-      png_ptr->background.index = buf[0];
+      background.index = buf[0];
 
       if (info_ptr && info_ptr->num_palette)
       {
@@ -1631,33 +1638,36 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
             return;
          }
 
-         png_ptr->background.red =
-             (png_uint_16)png_ptr->palette[buf[0]].red;
+         background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
+         background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
+         background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
+      }
 
-         png_ptr->background.green =
-             (png_uint_16)png_ptr->palette[buf[0]].green;
+      else
+         background.red = background.green = background.blue = 0;
 
-         png_ptr->background.blue =
-             (png_uint_16)png_ptr->palette[buf[0]].blue;
-      }
+      background.gray = 0;
    }
 
    else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
    {
-      png_ptr->background.red =
-      png_ptr->background.green =
-      png_ptr->background.blue =
-      png_ptr->background.gray = png_get_uint_16(buf);
+      background.index = 0;
+      background.red =
+      background.green =
+      background.blue =
+      background.gray = png_get_uint_16(buf);
    }
 
    else
    {
-      png_ptr->background.red = png_get_uint_16(buf);
-      png_ptr->background.green = png_get_uint_16(buf + 2);
-      png_ptr->background.blue = png_get_uint_16(buf + 4);
+      background.index = 0;
+      background.red = png_get_uint_16(buf);
+      background.green = png_get_uint_16(buf + 2);
+      background.blue = png_get_uint_16(buf + 4);
+      background.gray = 0;
    }
 
-   png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+   png_set_bKGD(png_ptr, info_ptr, &background);
 }
 #endif
 
@@ -1982,6 +1992,14 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
+   /* Need unit type, width, \0, height: minimum 4 bytes */
+   else if (length < 4)
+   {
+      png_warning(png_ptr, "sCAL chunk too short");
+      png_crc_finish(png_ptr, length);
+      return;
+   }
+
    png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
       length + 1);
 
@@ -2017,23 +2035,29 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* Validate the ASCII numbers, need two ASCII numbers separated by
     * a '\0' and they need to fit exactly in the chunk data.
     */
-   i = 0;
+   i = 1;
    state = 0;
 
-   if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
-       !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
+   if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
        i >= slength || png_ptr->chunkdata[i++] != 0)
       png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
 
+   else if (!PNG_FP_IS_POSITIVE(state))
+      png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width");
+
    else
    {
       png_size_t heighti = i;
 
-      if (png_ptr->chunkdata[i] == 45 /* negative height */ ||
-          !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
+      state = 0;
+      if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
           i != slength)
          png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
 
+      else if (!PNG_FP_IS_POSITIVE(state))
+         png_warning(png_ptr,
+            "Invalid sCAL chunk ignored: non-positive height");
+
       else
          /* This is the (only) success case. */
          png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
@@ -2660,6 +2684,14 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask)
 {
    png_debug(1, "in png_combine_row");
 
+   /* Added in 1.5.4: the row_info should match the information returned by any
+    * call to png_read_update_info at this point.  Do not continue if we got
+    * this wrong.
+    */
+   if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=
+          PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width))
+      png_error(png_ptr, "internal row size calculation error");
+
    if (mask == 0xff)
    {
       png_memcpy(row, png_ptr->row_buf + 1,
@@ -3398,7 +3430,9 @@ png_read_start_row(png_structp png_ptr)
 
    png_debug(1, "in png_read_start_row");
    png_ptr->zstream.avail_in = 0;
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
    png_init_read_transformations(png_ptr);
+#endif
 #ifdef PNG_READ_INTERLACING_SUPPORTED
    if (png_ptr->interlaced)
    {
index 2cfcf33bdf97f41486d09cf4a0888b2b07957153..7eaad7dd45d498708646c9d5f8c823884c1168f5 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngset.c - storage of image information into info struct
  *
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -94,15 +94,16 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
-   /* Previously these values were limited, however they must be
-    * wrong, therefore storing them (and setting PNG_INFO_gAMA)
-    * must be wrong too.
+   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
+    * occur.  Since the fixed point representation is assymetrical it is
+    * possible for 1/gamma to overflow the limit of 21474 and this means the
+    * gamma value must be at least 5/100000 and hence at most 20000.0.  For
+    * safety the limits here are a little narrower.  The values are 0.00016 to
+    * 6250.0, which are truely ridiculous gammma values (and will produce
+    * displays that are all black or all white.)
     */
-   if (file_gamma > (png_fixed_point)PNG_UINT_31_MAX)
-      png_warning(png_ptr, "Gamma too large, ignored");
-
-   else if (file_gamma <= 0)
-      png_warning(png_ptr, "Negative or zero gamma ignored");
+   if (file_gamma < 16 || file_gamma > 625000000)
+      png_warning(png_ptr, "Out of range gamma value ignored");
 
    else
    {
@@ -340,12 +341,12 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr,
    if (unit != 1 && unit != 2)
       png_error(png_ptr, "Invalid sCAL unit");
 
-   if (swidth == NULL || (lengthw = png_strlen(swidth)) <= 0 ||
-       swidth[0] == 45 /*'-'*/ || !png_check_fp_string(swidth, lengthw))
+   if (swidth == NULL || (lengthw = png_strlen(swidth)) == 0 ||
+       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
       png_error(png_ptr, "Invalid sCAL width");
 
-   if (sheight == NULL || (lengthh = png_strlen(sheight)) <= 0 ||
-       sheight[0] == 45 /*'-'*/ || !png_check_fp_string(sheight, lengthh))
+   if (sheight == NULL || (lengthh = png_strlen(sheight)) == 0 ||
+       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
       png_error(png_ptr, "Invalid sCAL height");
 
    info_ptr->scal_unit = (png_byte)unit;
@@ -545,7 +546,7 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
    png_set_sRGB(png_ptr, info_ptr, srgb_intent);
 
 #  ifdef PNG_gAMA_SUPPORTED
-   png_set_gAMA_fixed(png_ptr, info_ptr, 45455L);
+   png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
 #  endif
 
 #  ifdef PNG_cHRM_SUPPORTED
index 8d781faefecae306ff4c27cd391e10ee6b74cf05..93b2b3eb0f6f03bf4480210ba98e2b4c0dcd0209 100644 (file)
@@ -5,7 +5,7 @@
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  *
  * This code is released under the libpng license.
  * For conditions of distribution and use, see the disclaimer
 struct png_struct_def
 {
 #ifdef PNG_SETJMP_SUPPORTED
-   jmp_buf png_jmpbuf;            /* used in png_error */
+   jmp_buf longjmp_buffer;    /* used in png_error */
    png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */
 #endif
    png_error_ptr error_fn;    /* function for printing errors and aborting */
+#ifdef PNG_WARNINGS_SUPPORTED
    png_error_ptr warning_fn;  /* function for printing warnings */
+#endif
    png_voidp error_ptr;       /* user supplied struct for error functions */
    png_rw_ptr write_data_fn;  /* function for writing output data */
    png_rw_ptr read_data_fn;   /* function for reading input data */
@@ -64,11 +66,36 @@ struct png_struct_def
    z_stream zstream;          /* pointer to decompression structure (below) */
    png_bytep zbuf;            /* buffer for zlib */
    uInt zbuf_size;            /* size of zbuf (typically 65536) */
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Added in 1.5.4: state to keep track of whether the zstream has been
+ * initialized and if so whether it is for IDAT or some other chunk.
+ */
+#define PNG_ZLIB_UNINITIALIZED 0
+#define PNG_ZLIB_FOR_IDAT      1
+#define PNG_ZLIB_FOR_TEXT      2 /* anything other than IDAT */
+#define PNG_ZLIB_USE_MASK      3 /* bottom two bits */
+#define PNG_ZLIB_IN_USE        4 /* a flag value */
+
+   png_uint_32 zlib_state;       /* State of zlib initialization */
+/* End of material added at libpng 1.5.4 */
+
    int zlib_level;            /* holds zlib compression level */
    int zlib_method;           /* holds zlib compression method */
    int zlib_window_bits;      /* holds zlib compression window bits */
    int zlib_mem_level;        /* holds zlib compression memory level */
    int zlib_strategy;         /* holds zlib compression strategy */
+#endif
+/* Added at libpng 1.5.4 */
+#if defined(PNG_WRITE_COMPRESSED_TEXT_SUPPORTED) || \
+    defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED)
+   int zlib_text_level;            /* holds zlib compression level */
+   int zlib_text_method;           /* holds zlib compression method */
+   int zlib_text_window_bits;      /* holds zlib compression window bits */
+   int zlib_text_mem_level;        /* holds zlib compression memory level */
+   int zlib_text_strategy;         /* holds zlib compression strategy */
+#endif
+/* End of material added at libpng 1.5.4 */
 
    png_uint_32 width;         /* width of image in pixels */
    png_uint_32 height;        /* height of image in pixels */
@@ -84,6 +111,7 @@ struct png_struct_def
    png_bytep avg_row;         /* buffer to save "avg" row when filtering */
    png_bytep paeth_row;       /* buffer to save "Paeth" row when filtering */
    png_row_info row_info;     /* used for transformation routines */
+   png_size_t info_rowbytes;  /* Added in 1.5.4: cache of updated row bytes */
 
    png_uint_32 idat_size;     /* current IDAT size for read */
    png_uint_32 crc;           /* current chunk CRC value */
@@ -108,7 +136,8 @@ struct png_struct_def
    png_uint_16 filler;           /* filler bytes for pixel expansion */
 #endif
 
-#ifdef PNG_bKGD_SUPPORTED
+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+   defined(PNG_READ_ALPHA_MODE_SUPPORTED)
    png_byte background_gamma_type;
    png_fixed_point background_gamma;
    png_color_16 background;   /* background color in screen gamma space */
@@ -209,7 +238,7 @@ struct png_struct_def
 #endif
 
 #ifdef PNG_TIME_RFC1123_SUPPORTED
-   png_charp time_buffer; /* String to hold RFC 1123 time text */
+   char time_buffer[29]; /* String to hold RFC 1123 time text */
 #endif
 
 /* New members added in libpng-1.0.6 */
index a6a3ae489c1f5c975c606bcfc29862d3137c2458..9084ada624c38664ed1d26f4348fdab354d5357c 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngtest.c - a simple test program to test libpng
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -31,6 +31,8 @@
  * of files at once by typing "pngtest -m file1.png file2.png ..."
  */
 
+#define _POSIX_SOURCE 1
+
 #include "zlib.h"
 #include "png.h"
 /* Copied from pngpriv.h but only used in error messages below. */
@@ -779,7 +781,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
    int bit_depth, color_type;
 #ifdef PNG_SETJMP_SUPPORTED
 #ifdef USE_FAR_KEYWORD
-   jmp_buf png_jmpbuf;
+   jmp_buf tmp_jmpbuf;
 #endif
 #endif
 
@@ -848,7 +850,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
 #ifdef PNG_SETJMP_SUPPORTED
    pngtest_debug("Setting jmpbuf for read struct");
 #ifdef USE_FAR_KEYWORD
-   if (setjmp(png_jmpbuf))
+   if (setjmp(tmp_jmpbuf))
 #else
    if (setjmp(png_jmpbuf(read_ptr)))
 #endif
@@ -866,14 +868,14 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
       return (1);
    }
 #ifdef USE_FAR_KEYWORD
-   png_memcpy(png_jmpbuf(read_ptr), png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(png_jmpbuf(read_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
 #endif
 
 #ifdef PNG_WRITE_SUPPORTED
    pngtest_debug("Setting jmpbuf for write struct");
 #ifdef USE_FAR_KEYWORD
 
-   if (setjmp(png_jmpbuf))
+   if (setjmp(tmp_jmpbuf))
 #else
    if (setjmp(png_jmpbuf(write_ptr)))
 #endif
@@ -890,7 +892,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
    }
 
 #ifdef USE_FAR_KEYWORD
-   png_memcpy(png_jmpbuf(write_ptr), png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(png_jmpbuf(write_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
 #endif
 #endif
 #endif
@@ -913,6 +915,14 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
 #  endif
 #endif
 
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
+    * This is here just to make pngtest replicate the results from libpng
+    * versions prior to 1.5.4, and to test this new API.
+    */
+   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
+#endif
+
    if (status_dots_requested == 1)
    {
 #ifdef PNG_WRITE_SUPPORTED
@@ -1784,4 +1794,4 @@ main(int argc, char *argv[])
 }
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_2 Your_png_h_is_not_version_1_5_2;
+typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4;
index cdf10da7da6a67a8f50c6eb44c248e70ea6ab202..81f5f8438a9f0fa8b87cd0266334f72792febf8f 100644 (file)
Binary files a/l4/pkg/libpng/lib/dist/pngtest.png and b/l4/pkg/libpng/lib/dist/pngtest.png differ
index cf7622cdc6e4b0b220b7ab64f5d0e60bf6e3a2c7..6a6908dcd26892635ec6b1dd31d55ed848f9736c 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -442,7 +442,11 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
    /* At the start sp will point to the first byte to copy and dp to where
     * it is copied to.  ep always points just beyond the end of the row, so
     * the loop simply copies (channels-1) channels until sp reaches ep.
+    *
+    * at_start:        0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc.
+    *            nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc.
     */
+
    /* GA, GX, XG cases */
    if (row_info->channels == 2)
    {
@@ -450,7 +454,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
       {
          if (at_start) /* Skip initial filler */
             ++sp;
-         else          /* Skip initial channels and, for sp, the filler */
+         else          /* Skip initial channel and, for sp, the filler */
             sp += 2, ++dp;
 
          /* For a 1 pixel wide image there is nothing to do */
@@ -462,9 +466,9 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
 
       else if (row_info->bit_depth == 16)
       {
-         if (at_start)
+         if (at_start) /* Skip initial filler */
             sp += 2;
-         else
+         else          /* Skip initial channel and, for sp, the filler */
             sp += 4, dp += 2;
 
          while (sp < ep)
@@ -502,9 +506,9 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
 
       else if (row_info->bit_depth == 16)
       {
-         if (at_start)
+         if (at_start) /* Skip initial filler */
             sp += 2;
-         else
+         else          /* Skip initial channels and, for sp, the filler */
             sp += 8, dp += 6;
 
          while (sp < ep)
index 54c55dd4b67b0e253c3f0c2f2d3d5458ea19162f..6d1736c1540046c2288fe5bbd62b889042a80f72 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngvalid.c - validate libpng by constructing then reading png files.
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 2011 Glenn Randers-Pehrson
  * Written by John Cunningham Bowler
  *
@@ -19,6 +19,8 @@
  *   transformations performed by libpng.
  */
 
+#define _POSIX_SOURCE 1
+
 #include "png.h"
 #if PNG_LIBPNG_VER < 10500
 /* This delibarately lacks the PNG_CONST. */
@@ -46,9 +48,13 @@ typedef png_byte *png_const_bytep;
 #define PNG_COL_IN_INTERLACE_PASS(x, pass) \
    ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
 
-/* These are needed too for the defualt build: */
+/* These are needed too for the default build: */
 #define PNG_WRITE_16BIT_SUPPORTED
 #define PNG_READ_16BIT_SUPPORTED
+
+/* This comes from pnglibconf.h afer 1.5: */
+#define PNG_GAMMA_THRESHOLD_FIXED\
+   ((png_fixed_point)(PNG_GAMMA_THRESHOLD * 100000))
 #endif
 
 #include "zlib.h"   /* For crc32 */
@@ -108,6 +114,7 @@ static size_t safecatn(char *buffer, size_t bufsize, size_t pos, int n)
    return safecat(buffer, bufsize, pos, number);
 }
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d,
     int precision)
 {
@@ -115,59 +122,76 @@ static size_t safecatd(char *buffer, size_t bufsize, size_t pos, double d,
    sprintf(number, "%.*f", precision, d);
    return safecat(buffer, bufsize, pos, number);
 }
+#endif
 
 static PNG_CONST char invalid[] = "invalid";
 static PNG_CONST char sep[] = ": ";
 
-/* NOTE: this is indexed by ln2(bit_depth)! */
-static PNG_CONST char *bit_depths[8] =
-{
-   "1", "2", "4", "8", "16", invalid, invalid, invalid
-};
-
 static PNG_CONST char *colour_types[8] =
 {
    "greyscale", invalid, "truecolour", "indexed-colour",
    "greyscale with alpha", invalid, "truecolour with alpha", invalid
 };
 
-/* To get log-bit-depth from bit depth, returns 0 to 7 (7 on error). */
-static unsigned int
-log2depth(png_byte bit_depth)
+/* Generate random bytes.  This uses a boring repeatable algorithm and it
+ * is implemented here so that it gives the same set of numbers on every
+ * architecture.  It's a linear congruential generator (Knuth or Sedgewick
+ * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and
+ * Hill, "The Art of Electronics".
+ */
+static void
+make_random_bytes(png_uint_32* seed, void* pv, size_t size)
 {
-   switch (bit_depth)
-   {
-      case 1:
-         return 0;
+   png_uint_32 u0 = seed[0], u1 = seed[1];
+   png_bytep bytes = /*no cast required*/pv;
 
-      case 2:
-         return 1;
-
-      case 4:
-         return 2;
+   /* There are thirty three bits, the next bit in the sequence is bit-33 XOR
+    * bit-20.  The top 1 bit is in u1, the bottom 32 are in u0.
+    */
+   size_t i;
+   for (i=0; i<size; ++i)
+   {
+      /* First generate 8 new bits then shift them in at the end. */
+      png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff;
+      u1 <<= 8;
+      u1 |= u0 >> 24;
+      u0 <<= 8;
+      u0 |= u;
+      *bytes++ = (png_byte)u;
+   }
 
-      case 8:
-         return 3;
+   seed[0] = u0;
+   seed[1] = u1;
+}
 
-      case 16:
-         return 4;
+static void
+make_four_random_bytes(png_uint_32* seed, png_bytep bytes)
+{
+   make_random_bytes(seed, bytes, 4);
+}
 
-      default:
-         return 7;
-   }
+static void
+randomize(void *pv, size_t size)
+{
+   static png_uint_32 random_seed[2] = {0x56789abc, 0xd};
+   make_random_bytes(random_seed, pv, size);
 }
 
+#define RANDOMIZE(this) randomize(&(this), sizeof (this))
+
 /* A numeric ID based on PNG file characteristics.  The 'do_interlace' field
  * simply records whether pngvalid did the interlace itself or whether it
- * was done by libpng.  Width and height must be less than 256.
+ * was done by libpng.  Width and height must be less than 256.  'palette' is an
+ * index of the palette to use for formats with a palette (0 otherwise.)
  */
-#define FILEID(col, depth, interlace, width, height, do_interlace) \
-   ((png_uint_32)((col) + ((depth)<<3) + ((interlace)<<8) + \
+#define FILEID(col, depth, palette, interlace, width, height, do_interlace) \
+   ((png_uint_32)((col) + ((depth)<<3) + ((palette)<<8) + ((interlace)<<13) + \
     (((do_interlace)!=0)<<15) + ((width)<<16) + ((height)<<24)))
 
 #define COL_FROM_ID(id) ((png_byte)((id)& 0x7U))
 #define DEPTH_FROM_ID(id) ((png_byte)(((id) >> 3) & 0x1fU))
-#define INTERLACE_FROM_ID(id) ((int)(((id) >> 8) & 0x3))
+#define PALETTE_FROM_ID(id) ((int)(((id) >> 8) & 0x1f))
+#define INTERLACE_FROM_ID(id) ((int)(((id) >> 13) & 0x3))
 #define DO_INTERLACE_FROM_ID(id) ((int)(((id)>>15) & 1))
 #define WIDTH_FROM_ID(id) (((id)>>16) & 0xff)
 #define HEIGHT_FROM_ID(id) (((id)>>24) & 0xff)
@@ -175,20 +199,29 @@ log2depth(png_byte bit_depth)
 /* Utility to construct a standard name for a standard image. */
 static size_t
 standard_name(char *buffer, size_t bufsize, size_t pos, png_byte colour_type,
-    int log_bit_depth, int interlace_type, png_uint_32 w, png_uint_32 h,
-    int do_interlace)
+    int bit_depth, int npalette, int interlace_type,
+    png_uint_32 w, png_uint_32 h, int do_interlace)
 {
    pos = safecat(buffer, bufsize, pos, colour_types[colour_type]);
+   if (npalette > 0)
+   {
+      pos = safecat(buffer, bufsize, pos, "[");
+      pos = safecatn(buffer, bufsize, pos, npalette);
+      pos = safecat(buffer, bufsize, pos, "]");
+   }
    pos = safecat(buffer, bufsize, pos, " ");
-   pos = safecat(buffer, bufsize, pos, bit_depths[log_bit_depth]);
-   pos = safecat(buffer, bufsize, pos, " bit ");
+   pos = safecatn(buffer, bufsize, pos, bit_depth);
+   pos = safecat(buffer, bufsize, pos, " bit");
 
    if (interlace_type != PNG_INTERLACE_NONE)
-      pos = safecat(buffer, bufsize, pos, "interlaced");
-   if (do_interlace)
-      pos = safecat(buffer, bufsize, pos, "(pngvalid)");
-   else
-      pos = safecat(buffer, bufsize, pos, "(libpng)");
+   {
+      pos = safecat(buffer, bufsize, pos, " interlaced");
+      if (do_interlace)
+         pos = safecat(buffer, bufsize, pos, "(pngvalid)");
+      else
+         pos = safecat(buffer, bufsize, pos, "(libpng)");
+   }
+
    if (w > 0 || h > 0)
    {
       pos = safecat(buffer, bufsize, pos, " ");
@@ -204,7 +237,7 @@ static size_t
 standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
 {
    return standard_name(buffer, bufsize, pos, COL_FROM_ID(id),
-      log2depth(DEPTH_FROM_ID(id)), INTERLACE_FROM_ID(id),
+      DEPTH_FROM_ID(id), PALETTE_FROM_ID(id), INTERLACE_FROM_ID(id),
       WIDTH_FROM_ID(id), HEIGHT_FROM_ID(id), DO_INTERLACE_FROM_ID(id));
 }
 
@@ -225,15 +258,29 @@ standard_name_from_id(char *buffer, size_t bufsize, size_t pos, png_uint_32 id)
 #  define READ_BDHI 3
 #endif
 
+/* The following defines the number of different palettes to generate for
+ * each log bit depth of a colour type 3 standard image.
+ */
+#define PALETTE_COUNT(bit_depth) ((bit_depth) > 4 ? 1 : 16)
+
 static int
-next_format(png_bytep colour_type, png_bytep bit_depth)
+next_format(png_bytep colour_type, png_bytep bit_depth, int* palette_number)
 {
    if (*bit_depth == 0)
    {
-      *colour_type = 0, *bit_depth = 1;
+      *colour_type = 0, *bit_depth = 1, *palette_number = 0;
       return 1;
    }
 
+   if (*colour_type == 3)
+   {
+      /* Add multiple palettes for colour type 3. */
+      if (++*palette_number < PALETTE_COUNT(*bit_depth))
+         return 1;
+
+      *palette_number = 0;
+   }
+
    *bit_depth = (png_byte)(*bit_depth << 1);
 
    /* Palette images are restricted to 8 bit depth */
@@ -272,6 +319,7 @@ next_format(png_bytep colour_type, png_bytep bit_depth)
    }
 }
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 static unsigned int
 sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
     png_uint_32 x, unsigned int sample_index)
@@ -290,8 +338,9 @@ sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
       if (colour_type & 4)
          bit_index += x; /* Alpha channel */
 
+      /* Multiple channels; select one: */
       if (colour_type & (2+4))
-         bit_index += sample_index * bit_depth; /* Multiple channels: select one */
+         bit_index += sample_index * bit_depth;
    }
 
    /* Return the sample from the row as an integer. */
@@ -308,6 +357,7 @@ sample(png_const_bytep row, png_byte colour_type, png_byte bit_depth,
    bit_index &= 7;
    return (result >> (8-bit_index-bit_depth)) & ((1U<<bit_depth)-1);
 }
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
 /* Copy a single pixel, of a given size, from one buffer to another -
  * while this is basically bit addressed there is an implicit assumption
@@ -389,6 +439,14 @@ typedef struct png_store_buffer
 
 #define FILE_NAME_SIZE 64
 
+typedef struct store_palette_entry /* record of a single palette entry */
+{
+   png_byte red;
+   png_byte green;
+   png_byte blue;
+   png_byte alpha;
+} store_palette_entry, store_palette[256];
+
 typedef struct png_store_file
 {
    struct png_store_file*  next;      /* as many as you like... */
@@ -396,6 +454,8 @@ typedef struct png_store_file
    png_uint_32             id;        /* must be correct (see FILEID) */
    png_size_t              datacount; /* In this (the last) buffer */
    png_store_buffer        data;      /* Last buffer in file */
+   int                     npalette;  /* Number of entries in palette */
+   store_palette_entry*    palette;   /* May be NULL */
 } png_store_file;
 
 /* The following is a pool of memory allocated by a single libpng read or write
@@ -448,7 +508,9 @@ typedef struct png_store
    png_store_buffer*  next;     /* Set when reading */
    png_size_t         readpos;  /* Position in *next */
    png_byte*          image;    /* Buffer for reading interlaced images */
-   size_t             cb_image; /* Size of this buffer */
+   png_size_t         cb_image; /* Size of this buffer */
+   png_size_t         cb_row;   /* Row size of the image(s) */
+   png_uint_32        image_h;  /* Number of rows in a single image */
    store_pool         read_memory_pool;
 
    /* Write fields */
@@ -459,37 +521,20 @@ typedef struct png_store
    char               wname[FILE_NAME_SIZE];
    png_store_buffer   new;      /* The end of the new PNG file being written. */
    store_pool         write_memory_pool;
+   store_palette_entry* palette;
+   int                  npalette;
 } png_store;
 
 /* Initialization and cleanup */
 static void
-store_pool_mark(png_byte *mark)
+store_pool_mark(png_bytemark)
 {
-   /* Generate a new mark.  This uses a boring repeatable algorithm and it is
-    * implemented here so that it gives the same set of numbers on every
-    * architecture.  It's a linear congruential generator (Knuth or Sedgewick
-    * "Algorithms") but it comes from the 'feedback taps' table in Horowitz and
-    * Hill, "The Art of Electronics".
-    */
-   static png_uint_32 u0 = 0x12345678, u1 = 1;
+   static png_uint_32 store_seed[2] = { 0x12345678, 1};
 
-   /* There are thirty three bits, the next bit in the sequence is bit-33 XOR
-    * bit-20.  The top 1 bit is in u1, the bottom 32 are in u0.
-    */
-   int i;
-   for (i=0; i<4; ++i)
-   {
-      /* First generate 8 new bits then shift them in at the end. */
-      png_uint_32 u = ((u0 >> (20-8)) ^ ((u1 << 7) | (u0 >> (32-7)))) & 0xff;
-      u1 <<= 8;
-      u1 |= u0 >> 24;
-      u0 <<= 8;
-      u0 |= u;
-      *mark++ = (png_byte)u;
-   }
+   make_four_random_bytes(store_seed, mark);
 }
 
-/* Use this for random 32 bit values, this function makes sure the result is
+/* Use this for random 32 bit values; this function makes sure the result is
  * non-zero.
  */
 static png_uint_32
@@ -544,40 +589,14 @@ store_init(png_store* ps)
    ps->readpos = 0;
    ps->image = NULL;
    ps->cb_image = 0;
+   ps->cb_row = 0;
+   ps->image_h = 0;
    ps->pwrite = NULL;
    ps->piwrite = NULL;
    ps->writepos = 0;
    ps->new.prev = NULL;
-}
-
-/* This somewhat odd function is used when reading an image to ensure that the
- * buffer is big enough - this is why a png_structp is available.
- */
-static void
-store_ensure_image(png_store *ps, png_structp pp, size_t cb)
-{
-   if (ps->cb_image < cb)
-   {
-      if (ps->image != NULL)
-      {
-         free(ps->image-1);
-         ps->cb_image = 0;
-      }
-
-      /* The buffer is deliberately mis-aligned. */
-      ps->image = malloc(cb+1);
-      if (ps->image == NULL)
-         png_error(pp, "OOM allocating image buffer");
-
-      ++(ps->image);
-      ps->cb_image = cb;
-   }
-
-   /* And, for error checking, the whole buffer is set to '1' - this
-    * matches what happens with the 'size' test images on write and also
-    * matches the unused bits in the test rows.
-    */
-   memset(ps->image, 0xff, cb);
+   ps->palette = NULL;
+   ps->npalette = 0;
 }
 
 static void
@@ -596,6 +615,12 @@ store_freenew(png_store *ps)
 {
    store_freebuffer(&ps->new);
    ps->writepos = 0;
+   if (ps->palette != NULL)
+   {
+      free(ps->palette);
+      ps->palette = NULL;
+      ps->npalette = 0;
+   }
 }
 
 static void
@@ -625,6 +650,12 @@ store_freefile(png_store_file **ppf)
 
       store_freebuffer(&(*ppf)->data);
       (*ppf)->datacount = 0;
+      if ((*ppf)->palette != NULL)
+      {
+         free((*ppf)->palette);
+         (*ppf)->palette = NULL;
+         (*ppf)->npalette = 0;
+      }
       free(*ppf);
       *ppf = NULL;
    }
@@ -645,6 +676,10 @@ store_storefile(png_store *ps, png_uint_32 id)
    pf->datacount = ps->writepos;
    ps->new.prev = NULL;
    ps->writepos = 0;
+   pf->palette = ps->palette;
+   pf->npalette = ps->npalette;
+   ps->palette = 0;
+   ps->npalette = 0;
 
    /* And save it. */
    pf->next = ps->saved;
@@ -691,6 +726,21 @@ store_message(png_store *ps, png_structp pp, char *buffer, size_t bufsize,
    return pos;
 }
 
+/* Verbose output to the error stream: */
+static void
+store_verbose(png_store *ps, png_structp pp, png_const_charp prefix,
+   png_const_charp message)
+{
+   char buffer[512];
+
+   if (prefix)
+      fputs(prefix, stderr);
+
+   (void)store_message(ps, pp, buffer, sizeof buffer, 0, message);
+   fputs(buffer, stderr);
+   fputc('\n', stderr);
+}
+
 /* Log an error or warning - the relevant count is always incremented. */
 static void
 store_log(png_store* ps, png_structp pp, png_const_charp message, int is_error)
@@ -704,19 +754,7 @@ store_log(png_store* ps, png_structp pp, png_const_charp message, int is_error)
       store_message(ps, pp, ps->error, sizeof ps->error, 0, message);
 
    if (ps->verbose)
-   {
-      char buffer[256];
-      size_t pos;
-
-      if (is_error)
-         pos = safecat(buffer, sizeof buffer, 0, "error: ");
-      else
-         pos = safecat(buffer, sizeof buffer, 0, "warning: ");
-
-      store_message(ps, pp, buffer, sizeof buffer, pos, message);
-      fputs(buffer, stderr);
-      fputc('\n', stderr);
-   }
+      store_verbose(ps, pp, is_error ? "error: " : "warning: ", message);
 }
 
 /* Functions to use as PNG callbacks. */
@@ -746,6 +784,141 @@ store_warning(png_structp pp, png_const_charp message)
       ps->saw_warning = 1;
 }
 
+/* These somewhat odd functions are used when reading an image to ensure that
+ * the buffer is big enough, the png_structp is for errors.
+ */
+/* Return a single row from the correct image. */
+static png_bytep
+store_image_row(PNG_CONST png_store* ps, png_structp pp, int nImage,
+   png_uint_32 y)
+{
+   png_size_t coffset = (nImage * ps->image_h + y) * (ps->cb_row + 5) + 2;
+
+   if (ps->image == NULL)
+      png_error(pp, "no allocated image");
+
+   if (coffset + ps->cb_row + 3 > ps->cb_image)
+      png_error(pp, "image too small");
+
+   return ps->image + coffset;
+}
+
+static void
+store_image_free(png_store *ps, png_structp pp)
+{
+   if (ps->image != NULL)
+   {
+      png_bytep image = ps->image;
+
+      if (image[-1] != 0xed || image[ps->cb_image] != 0xfe)
+      {
+         if (pp != NULL)
+            png_error(pp, "png_store image overwrite (1)");
+         else
+            store_log(ps, NULL, "png_store image overwrite (2)", 1);
+      }
+
+      ps->image = NULL;
+      ps->cb_image = 0;
+      --image;
+      free(image);
+   }
+}
+
+static void
+store_ensure_image(png_store *ps, png_structp pp, int nImages, png_size_t cbRow,
+   png_uint_32 cRows)
+{
+   png_size_t cb = nImages * cRows * (cbRow + 5);
+
+   if (ps->cb_image < cb)
+   {
+      png_bytep image;
+
+      store_image_free(ps, pp);
+
+      /* The buffer is deliberately mis-aligned. */
+      image = malloc(cb+2);
+      if (image == NULL)
+      {
+         /* Called from the startup - ignore the error for the moment. */
+         if (pp == NULL)
+            return;
+
+         png_error(pp, "OOM allocating image buffer");
+      }
+
+      /* These magic tags are used to detect overwrites above. */
+      ++image;
+      image[-1] = 0xed;
+      image[cb] = 0xfe;
+
+      ps->image = image;
+      ps->cb_image = cb;
+   }
+
+   /* We have an adequate sized image; lay out the rows.  There are 2 bytes at
+    * the start and three at the end of each (this ensures that the row
+    * alignment starts out odd - 2+1 and changes for larger images on each row.)
+    */
+   ps->cb_row = cbRow;
+   ps->image_h = cRows;
+
+   /* For error checking, the whole buffer is set to '1' - this matches what
+    * happens with the 'size' test images on write and also matches the unused
+    * bits in the test rows.
+    */
+   memset(ps->image, 0xff, cb);
+
+   /* Then put in the marks. */
+   while (--nImages >= 0)
+   {
+      png_uint_32 y;
+
+      for (y=0; y<cRows; ++y)
+      {
+         png_bytep row = store_image_row(ps, pp, nImages, y);
+
+         /* The markers: */
+         row[-2] = 190;
+         row[-1] = 239;
+         row[cbRow] = 222;
+         row[cbRow+1] = 173;
+         row[cbRow+2] = 17;
+      }
+   }
+}
+
+static void
+store_image_check(PNG_CONST png_store* ps, png_structp pp, int iImage)
+{
+   png_const_bytep image = ps->image;
+
+   if (image[-1] != 0xed || image[ps->cb_image] != 0xfe)
+      png_error(pp, "image overwrite");
+   else
+   {
+      png_size_t cbRow = ps->cb_row;
+      png_uint_32 rows = ps->image_h;
+
+      image += iImage * (cbRow+5) * ps->image_h;
+
+      image += 2; /* skip image first row markers */
+
+      while (rows-- > 0)
+      {
+         if (image[-2] != 190 || image[-1] != 239)
+            png_error(pp, "row start overwritten");
+
+         if (image[cbRow] != 222 || image[cbRow+1] != 173 ||
+            image[cbRow+2] != 17)
+            png_error(pp, "row end overwritten");
+
+         image += cbRow+5;
+      }
+   }
+}
+
 static void
 store_write(png_structp pp, png_bytep pb, png_size_t st)
 {
@@ -789,6 +962,7 @@ store_read_buffer_size(png_store *ps)
    return ps->current->datacount;
 }
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* Return total bytes available for read. */
 static size_t
 store_read_buffer_avail(png_store *ps)
@@ -813,6 +987,7 @@ store_read_buffer_avail(png_store *ps)
 
    return 0;
 }
+#endif
 
 static int
 store_read_buffer_next(png_store *ps)
@@ -894,6 +1069,44 @@ store_progressive_read(png_store *ps, png_structp pp, png_infop pi)
    while (store_read_buffer_next(ps));
 }
 
+/* The caller must fill this in: */
+static store_palette_entry *
+store_write_palette(png_store *ps, int npalette)
+{
+   if (ps->pwrite == NULL)
+      store_log(ps, NULL, "attempt to write palette without write stream", 1);
+
+   if (ps->palette != NULL)
+      png_error(ps->pwrite, "multiple store_write_palette calls");
+
+   /* This function can only return NULL if called with '0'! */
+   if (npalette > 0)
+   {
+      ps->palette = malloc(npalette * sizeof *ps->palette);
+
+      if (ps->palette == NULL)
+         png_error(ps->pwrite, "store new palette: OOM");
+
+      ps->npalette = npalette;
+   }
+
+   return ps->palette;
+}
+
+static store_palette_entry *
+store_current_palette(png_store *ps, int *npalette)
+{
+   /* This is an internal error (the call has been made outside a read
+    * operation.)
+    */
+   if (ps->current == NULL)
+      store_log(ps, ps->pread, "no current stream for palette", 1);
+
+   /* The result may be null if there is no palette. */
+   *npalette = ps->current->npalette;
+   return ps->current->palette;
+}
+
 /***************************** MEMORY MANAGEMENT*** ***************************/
 /* A store_memory is simply the header for an allocated block of memory.  The
  * pointer returned to libpng is just after the end of the header block, the
@@ -1258,13 +1471,7 @@ store_delete(png_store *ps)
    store_write_reset(ps);
    store_read_reset(ps);
    store_freefile(&ps->saved);
-
-   if (ps->image != NULL)
-   {
-      free(ps->image-1);
-      ps->image = NULL;
-      ps->cb_image = 0;
-   }
+   store_image_free(ps, NULL);
 }
 
 /*********************** PNG FILE MODIFICATION ON READ ************************/
@@ -1310,11 +1517,19 @@ typedef struct png_modifier
     */
    double                   maxout8;  /* Maximum output value error */
    double                   maxabs8;  /* Absolute sample error 0..1 */
+   double                   maxcalc8; /* Absolute sample error 0..1 */
    double                   maxpc8;   /* Percentage sample error 0..100% */
    double                   maxout16; /* Maximum output value error */
    double                   maxabs16; /* Absolute sample error 0..1 */
+   double                   maxcalc16;/* Absolute sample error 0..1 */
    double                   maxpc16;  /* Percentage sample error 0..100% */
 
+   /* Log limits - values above this are logged, but not necessarily
+    * warned.
+    */
+   double                   log8;     /* Absolute error in 8 bits to log */
+   double                   log16;    /* Absolute error in 16 bits to log */
+
    /* Logged 8 and 16 bit errors ('output' values): */
    double                   error_gray_2;
    double                   error_gray_4;
@@ -1322,6 +1537,7 @@ typedef struct png_modifier
    double                   error_gray_16;
    double                   error_color_8;
    double                   error_color_16;
+   double                   error_indexed;
 
    /* Flags: */
    /* Whether or not to interlace. */
@@ -1341,11 +1557,24 @@ typedef struct png_modifier
    unsigned int             use_input_precision_sbit :1;
    unsigned int             use_input_precision_16to8 :1;
 
+   /* If set assume that the calculation bit depth is set by the input
+    * precision, not the output precision.
+    */
+   unsigned int             calculations_use_input_precision :1;
+
+   /* If set assume that the calculations are done in 16 bits even if both input
+    * and output are 8 bit or less.
+    */
+   unsigned int             assume_16_bit_calculations :1;
+
    /* Which gamma tests to run: */
    unsigned int             test_gamma_threshold :1;
    unsigned int             test_gamma_transform :1; /* main tests */
    unsigned int             test_gamma_sbit :1;
-   unsigned int             test_gamma_strip16 :1;
+   unsigned int             test_gamma_scale16 :1;
+   unsigned int             test_gamma_background :1;
+   unsigned int             test_gamma_alpha_mode :1;
+   unsigned int             test_gamma_expand16 :1;
 
    unsigned int             log :1;   /* Log max error */
 
@@ -1358,35 +1587,6 @@ typedef struct png_modifier
    png_byte                 buffer[1024];
 } png_modifier;
 
-static double abserr(png_modifier *pm, png_byte bit_depth)
-{
-   return bit_depth == 16 ? pm->maxabs16 : pm->maxabs8;
-}
-
-static double pcerr(png_modifier *pm, png_byte bit_depth)
-{
-   return (bit_depth == 16 ? pm->maxpc16 : pm->maxpc8) * .01;
-}
-
-static double outerr(png_modifier *pm, png_byte bit_depth)
-{
-   /* There is a serious error in the 2 and 4 bit grayscale transform because
-    * the gamma table value (8 bits) is simply shifted, not rounded, so the
-    * error in 4 bit greyscale gamma is up to the value below.  This is a hack
-    * to allow pngvalid to succeed:
-    */
-   if (bit_depth == 2)
-      return .73182-.5;
-
-   if (bit_depth == 4)
-      return .90644-.5;
-
-   if (bit_depth == 16)
-     return pm->maxout16;
-
-   return pm->maxout8;
-}
-
 /* This returns true if the test should be stopped now because it has already
  * failed and it is running silently.
  */
@@ -1404,10 +1604,14 @@ modifier_init(png_modifier *pm)
    pm->modifications = NULL;
    pm->state = modifier_start;
    pm->sbitlow = 1U;
-   pm->maxout8 = pm->maxpc8 = pm->maxabs8 = 0;
-   pm->maxout16 = pm->maxpc16 = pm->maxabs16 = 0;
+   pm->ngammas = 0;
+   pm->gammas = 0;
+   pm->maxout8 = pm->maxpc8 = pm->maxabs8 = pm->maxcalc8 = 0;
+   pm->maxout16 = pm->maxpc16 = pm->maxabs16 = pm->maxcalc16 = 0;
+   pm->log8 = pm->log16 = 0; /* Means 'off' */
    pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
    pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0;
+   pm->error_indexed = 0;
    pm->interlace_type = PNG_INTERLACE_NONE;
    pm->test_standard = 0;
    pm->test_size = 0;
@@ -1415,56 +1619,197 @@ modifier_init(png_modifier *pm)
    pm->use_input_precision = 0;
    pm->use_input_precision_sbit = 0;
    pm->use_input_precision_16to8 = 0;
+   pm->calculations_use_input_precision = 0;
    pm->test_gamma_threshold = 0;
    pm->test_gamma_transform = 0;
    pm->test_gamma_sbit = 0;
-   pm->test_gamma_strip16 = 0;
+   pm->test_gamma_scale16 = 0;
+   pm->test_gamma_background = 0;
+   pm->test_gamma_alpha_mode = 0;
+   pm->test_gamma_expand16 = 0;
    pm->log = 0;
 
    /* Rely on the memset for all the other fields - there are no pointers */
 }
 
-/* One modification structure must be provided for each chunk to be modified (in
- * fact more than one can be provided if multiple separate changes are desired
- * for a single chunk.)  Modifications include adding a new chunk when a
- * suitable chunk does not exist.
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+/* If pm->calculations_use_input_precision is set then operations will happen
+ * with only 8 bit precision unless both the input and output bit depth are 16.
  *
- * The caller of modify_fn will reset the CRC of the chunk and record 'modified'
- * or 'added' as appropriate if the modify_fn returns 1 (true).  If the
- * modify_fn is NULL the chunk is simply removed.
+ * If pm->assume_16_bit_calculations is set then even 8 bit calculations use 16
+ * bit precision.  This only affects those of the following limits that pertain
+ * to a calculation - not a digitization operation!
  */
-typedef struct png_modification
+static double abserr(png_modifier *pm, int in_depth, int out_depth)
 {
-   struct png_modification *next;
-   png_uint_32              chunk;
-
-   /* If the following is NULL all matching chunks will be removed: */
-   int                    (*modify_fn)(struct png_modifier *pm,
-                               struct png_modification *me, int add);
-
-   /* If the following is set to PLTE, IDAT or IEND and the chunk has not been
-    * found and modified (and there is a modify_fn) the modify_fn will be called
-    * to add the chunk before the relevant chunk.
+   /* Absolute error permitted in linear values - affected by the bit depth of
+    * the calculations.
     */
-   png_uint_32              add;
-   unsigned int             modified :1;     /* Chunk was modified */
-   unsigned int             added    :1;     /* Chunk was added */
-   unsigned int             removed  :1;     /* Chunk was removed */
-} png_modification;
+   if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
+      !pm->calculations_use_input_precision)))
+      return pm->maxabs16;
+   else
+      return pm->maxabs8;
+}
 
-static void modification_reset(png_modification *pmm)
+static double calcerr(png_modifier *pm, int in_depth, int out_depth)
 {
-   if (pmm != NULL)
-   {
-      pmm->modified = 0;
-      pmm->added = 0;
-      pmm->removed = 0;
-      modification_reset(pmm->next);
-   }
+   /* Error in the linear composition arithmetic - only relevant when
+    * composition actually happens (0 < alpha < 1).
+    */
+   if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
+      !pm->calculations_use_input_precision)))
+      return pm->maxcalc16;
+   else
+      return pm->maxcalc8;
 }
 
-static void
-modification_init(png_modification *pmm)
+static double pcerr(png_modifier *pm, int in_depth, int out_depth)
+{
+   /* Percentage error permitted in the linear values.  Note that the specified
+    * value is a percentage but this routine returns a simple number.
+    */
+   if (pm->assume_16_bit_calculations || (out_depth == 16 && (in_depth == 16 ||
+      !pm->calculations_use_input_precision)))
+      return pm->maxpc16 * .01;
+   else
+      return pm->maxpc8 * .01;
+}
+
+/* Output error - the error in the encoded value.  This is determined by the
+ * digitization of the output so can be +/-0.5 in the actual output value.  In
+ * the expand_16 case with the current code in libpng the expand happens after
+ * all the calculations are done in 8 bit arithmetic, so even though the output
+ * depth is 16 the output error is determined by the 8 bit calculation.
+ *
+ * This limit is not determined by the bit depth of internal calculations.
+ *
+ * The specified parameter does *not* include the base .5 digitization error but
+ * it is added here.
+ */
+static double outerr(png_modifier *pm, int in_depth, int out_depth)
+{
+   /* There is a serious error in the 2 and 4 bit grayscale transform because
+    * the gamma table value (8 bits) is simply shifted, not rounded, so the
+    * error in 4 bit greyscale gamma is up to the value below.  This is a hack
+    * to allow pngvalid to succeed:
+    *
+    * TODO: fix this in libpng
+    */
+   if (out_depth == 2)
+      return .73182-.5;
+
+   if (out_depth == 4)
+      return .90644-.5;
+
+   if (out_depth == 16 && (in_depth == 16 ||
+      !pm->calculations_use_input_precision))
+      return pm->maxout16;
+
+   /* This is the case where the value was calculated at 8-bit precision then
+    * scaled to 16 bits.
+    */
+   else if (out_depth == 16)
+      return pm->maxout8 * 257;
+
+   else
+      return pm->maxout8;
+}
+
+/* This does the same thing as the above however it returns the value to log,
+ * rather than raising a warning.  This is useful for debugging to track down
+ * exactly what set of parameters cause high error values.
+ */
+static double outlog(png_modifier *pm, int in_depth, int out_depth)
+{
+   /* The command line parameters are either 8 bit (0..255) or 16 bit (0..65535)
+    * and so must be adjusted for low bit depth grayscale:
+    */
+   if (out_depth <= 8)
+   {
+      if (pm->log8 == 0) /* switched off */
+         return 256;
+
+      if (out_depth < 8)
+         return pm->log8 / 255 * ((1<<out_depth)-1);
+
+      return pm->log8;
+   }
+
+   if (out_depth == 16 && (in_depth == 16 ||
+      !pm->calculations_use_input_precision))
+   {
+      if (pm->log16 == 0)
+         return 65536;
+
+      return pm->log16;
+   }
+
+   /* This is the case where the value was calculated at 8-bit precision then
+    * scaled to 16 bits.
+    */
+   if (pm->log8 == 0)
+      return 65536;
+
+   return pm->log8 * 257;
+}
+
+/* This complements the above by providing the appropriate quantization for the
+ * final value.  Normally this would just be quantization to an integral value,
+ * but in the 8 bit calculation case it's actually quantization to a multiple of
+ * 257!
+ */
+static int output_quantization_factor(png_modifier *pm, int in_depth,
+   int out_depth)
+{
+   if (out_depth == 16 && in_depth != 16
+      && pm->calculations_use_input_precision)
+      return 257;
+   else
+      return 1;
+}
+
+/* One modification structure must be provided for each chunk to be modified (in
+ * fact more than one can be provided if multiple separate changes are desired
+ * for a single chunk.)  Modifications include adding a new chunk when a
+ * suitable chunk does not exist.
+ *
+ * The caller of modify_fn will reset the CRC of the chunk and record 'modified'
+ * or 'added' as appropriate if the modify_fn returns 1 (true).  If the
+ * modify_fn is NULL the chunk is simply removed.
+ */
+typedef struct png_modification
+{
+   struct png_modification *next;
+   png_uint_32              chunk;
+
+   /* If the following is NULL all matching chunks will be removed: */
+   int                    (*modify_fn)(struct png_modifier *pm,
+                               struct png_modification *me, int add);
+
+   /* If the following is set to PLTE, IDAT or IEND and the chunk has not been
+    * found and modified (and there is a modify_fn) the modify_fn will be called
+    * to add the chunk before the relevant chunk.
+    */
+   png_uint_32              add;
+   unsigned int             modified :1;     /* Chunk was modified */
+   unsigned int             added    :1;     /* Chunk was added */
+   unsigned int             removed  :1;     /* Chunk was removed */
+} png_modification;
+
+static void modification_reset(png_modification *pmm)
+{
+   if (pmm != NULL)
+   {
+      pmm->modified = 0;
+      pmm->added = 0;
+      pmm->removed = 0;
+      modification_reset(pmm->next);
+   }
+}
+
+static void
+modification_init(png_modification *pmm)
 {
    memset(pmm, 0, sizeof *pmm);
    pmm->next = NULL;
@@ -1586,7 +1931,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
                store_read_imp(&pm->this, pb, cb);
                pb += cb;
                st -= cb;
-               if (st <= 0) return;
+               if (st == 0) return;
             }
 
             /* No more bytes to flush, read a header, or handle a pending
@@ -1813,6 +2158,7 @@ set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id,
 
    return set_store_for_read(&pm->this, ppi, id, name);
 }
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
 /***************************** STANDARD PNG FILES *****************************/
 /* Standard files - write and save standard files. */
@@ -1840,9 +2186,170 @@ set_modifier_for_read(png_modifier *pm, png_infopp ppi, png_uint_32 id,
  * a maximum width of 16 pixels (for the 64bpp case.)  They also have a maximum
  * height of 16 rows.  The width and height are stored in the FILEID and, being
  * non-zero, indicate a size file.
+ *
+ * For palette image (colour type 3) multiple transform images are stored with
+ * the same bit depth to allow testing of more colour combinations -
+ * particularly important for testing the gamma code because libpng uses a
+ * different code path for palette images.  For size images a single palette is
+ * used.
+ */
+
+/* Make a 'standard' palette.  Because there are only 256 entries in a palette
+ * (maximum) this actually makes a random palette in the hope that enough tests
+ * will catch enough errors.  (Note that the same palette isn't produced every
+ * time for the same test - it depends on what previous tests have been run -
+ * but a given set of arguments to pngvalid will always produce the same palette
+ * at the same test!  This is why pseudo-random number generators are useful for
+ * testing.)
+ *
+ * The store must be open for write when this is called, otherwise an internal
+ * error will occur.  This routine contains its own magic number seed, so the
+ * palettes generated don't change if there are intervening errors (changing the
+ * calls to the store_mark seed.)
+ */
+static store_palette_entry *
+make_standard_palette(png_store* ps, int npalette, int do_tRNS)
+{
+   static png_uint_32 palette_seed[2] = { 0x87654321, 9 };
+
+   int i = 0;
+   png_byte values[256][4];
+
+   /* Always put in black and white plus the six primary and secondary colors.
+    */
+   for (; i<8; ++i)
+   {
+      values[i][1] = (i&1) ? 255 : 0;
+      values[i][2] = (i&2) ? 255 : 0;
+      values[i][3] = (i&4) ? 255 : 0;
+   }
+
+   /* Then add 62 greys (one quarter of the remaining 256 slots). */
+   {
+      int j = 0;
+      png_byte random_bytes[4];
+      png_byte need[256];
+
+      need[0] = 0; /*got black*/
+      memset(need+1, 1, (sizeof need)-2); /*need these*/
+      need[255] = 0; /*but not white*/
+
+      while (i<70)
+      {
+         png_byte b;
+
+         if (j==0)
+         {
+            make_four_random_bytes(palette_seed, random_bytes);
+            j = 4;
+         }
+
+         b = random_bytes[--j];
+         if (need[b])
+         {
+            values[i][1] = b;
+            values[i][2] = b;
+            values[i++][3] = b;
+         }
+      }
+   }
+
+   /* Finally add 192 colors at random - don't worry about matches to things we
+    * already have, chance is less than 1/65536.  Don't worry about greys,
+    * chance is the same, so we get a duplicate or extra gray less than 1 time
+    * in 170.
+    */
+   for (; i<256; ++i)
+      make_four_random_bytes(palette_seed, values[i]);
+
+   /* Fill in the alpha values in the first byte.  Just use all possible values
+    * (0..255) in an apparently random order:
+    */
+   {
+      store_palette_entry *palette;
+      png_byte selector[4];
+
+      make_four_random_bytes(palette_seed, selector);
+
+      if (do_tRNS)
+         for (i=0; i<256; ++i)
+            values[i][0] = (png_byte)(i ^ selector[0]);
+
+      else
+         for (i=0; i<256; ++i)
+            values[i][0] = 255; /* no transparency/tRNS chunk */
+
+      /* 'values' contains 256 ARGB values, but we only need 'npalette'.
+       * 'npalette' will always be a power of 2: 2, 4, 16 or 256.  In the low
+       * bit depth cases select colors at random, else it is difficult to have
+       * a set of low bit depth palette test with any chance of a reasonable
+       * range of colors.  Do this by randomly permuting values into the low
+       * 'npalette' entries using an XOR mask generated here.  This also
+       * permutes the npalette == 256 case in a potentially useful way (there is
+       * no relationship between palette index and the color value therein!)
+       */
+      palette = store_write_palette(ps, npalette);
+
+      for (i=0; i<npalette; ++i)
+      {
+         palette[i].alpha = values[i ^ selector[1]][0];
+         palette[i].red   = values[i ^ selector[1]][1];
+         palette[i].green = values[i ^ selector[1]][2];
+         palette[i].blue  = values[i ^ selector[1]][3];
+      }
+
+      return palette;
+   }
+}
+
+/* Initialize a standard palette on a write stream.  The 'do_tRNS' argument
+ * indicates whether or not to also set the tRNS chunk.
  */
+static void
+init_standard_palette(png_store *ps, png_structp pp, png_infop pi, int npalette,
+   int do_tRNS)
+{
+   store_palette_entry *ppal = make_standard_palette(ps, npalette, do_tRNS);
+
+   {
+      int i;
+      png_color palette[256];
+
+      /* Set all entries to detect overread errors. */
+      for (i=0; i<npalette; ++i)
+      {
+         palette[i].red = ppal[i].red;
+         palette[i].green = ppal[i].green;
+         palette[i].blue = ppal[i].blue;
+      }
+
+      /* Just in case fill in the rest with detectable values: */
+      for (; i<256; ++i)
+         palette[i].red = palette[i].green = palette[i].blue = 42;
+
+      png_set_PLTE(pp, pi, palette, npalette);
+   }
+
+   if (do_tRNS)
+   {
+      int i, j;
+      png_byte tRNS[256];
+
+      /* Set all the entries, but skip trailing opaque entries */
+      for (i=j=0; i<npalette; ++i)
+         if ((tRNS[i] = ppal[i].alpha) < 255)
+            j = i+1;
 
-/* The number of passes is related to the interlace type. There wass no libpng
+      /* Fill in the remainder with a detectable value: */
+      for (; i<256; ++i)
+         tRNS[i] = 24;
+
+      if (j > 0)
+         png_set_tRNS(pp, pi, tRNS, j, 0/*color*/);
+   }
+}
+
+/* The number of passes is related to the interlace type. There was no libpng
  * API to determine this prior to 1.5, so we need an inquiry function:
  */
 static int
@@ -1866,6 +2373,8 @@ bit_size(png_structp pp, png_byte colour_type, png_byte bit_depth)
 {
    switch (colour_type)
    {
+      default: png_error(pp, "invalid color type");
+
       case 0:  return bit_depth;
 
       case 2:  return 3*bit_depth;
@@ -1875,8 +2384,6 @@ bit_size(png_structp pp, png_byte colour_type, png_byte bit_depth)
       case 4:  return 2*bit_depth;
 
       case 6:  return 4*bit_depth;
-
-      default: png_error(pp, "invalid color type");
    }
 }
 
@@ -1884,12 +2391,7 @@ bit_size(png_structp pp, png_byte colour_type, png_byte bit_depth)
 #define TRANSFORM_ROWMAX (TRANSFORM_WIDTH*8U)
 #define SIZE_ROWMAX (16*8U) /* 16 pixels, max 8 bytes each - 128 bytes */
 #define STANDARD_ROWMAX TRANSFORM_ROWMAX /* The larger of the two */
-
-/* So the maximum image sizes are as follows.  A 'transform' image may require
- * more than 65535 bytes.  The size images are a maximum of 2046 bytes.
- */
-#define TRANSFORM_IMAGEMAX (TRANSFORM_ROWMAX * (png_uint_32)2048)
-#define SIZE_IMAGEMAX (SIZE_ROWMAX * 16U)
+#define SIZE_HEIGHTMAX 16 /* Maximum range of size images */
 
 static size_t
 transform_rowsize(png_structp pp, png_byte colour_type, png_byte bit_depth)
@@ -1925,6 +2427,7 @@ transform_height(png_structp pp, png_byte colour_type, png_byte bit_depth)
       case 48:
       case 64:
          return 2048;/* 4 x 65536 pixels. */
+#        define TRANSFORM_HEIGHTMAX 2048
 
       default:
          return 0;   /* Error, will be caught later */
@@ -2088,7 +2591,8 @@ transform_row(png_structp pp, png_byte buffer[TRANSFORM_ROWMAX],
  */
 static void
 make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
-    png_byte PNG_CONST bit_depth, int interlace_type, png_const_charp name)
+    png_byte PNG_CONST bit_depth, int palette_number, int interlace_type,
+    png_const_charp name)
 {
    context(ps, fault);
 
@@ -2111,17 +2615,32 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
          bit_depth, colour_type, interlace_type,
          PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
-      if (colour_type == 3) /* palette */
+#ifdef PNG_TEXT_SUPPORTED
       {
-         unsigned int i = 0;
-         png_color pal[256];
-
-         do
-            pal[i].red = pal[i].green = pal[i].blue = (png_byte)i;
-         while(++i < 256U);
+         static char key[] = "image name"; /* must be writeable */
+         size_t pos;
+         png_text text;
+         char copy[FILE_NAME_SIZE];
 
-         png_set_PLTE(pp, pi, pal, 256);
+         /* Use a compressed text string to test the correct interaction of text
+          * compression and IDAT compression.
+          */
+         text.compression = PNG_TEXT_COMPRESSION_zTXt;
+         text.key = key;
+         /* Yuck: the text must be writable! */
+         pos = safecat(copy, sizeof copy, 0, ps->wname);
+         text.text = copy;
+         text.text_length = pos;
+         text.itxt_length = 0;
+         text.lang = 0;
+         text.lang_key = 0;
+
+         png_set_text(pp, pi, &text, 1);
       }
+#endif
+
+      if (colour_type == 3) /* palette */
+         init_standard_palette(ps, pp, pi, 1U << bit_depth, 1/*do tRNS*/);
 
       png_write_info(pp, pi);
 
@@ -2155,11 +2674,32 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
          }
       }
 
+#ifdef PNG_TEXT_SUPPORTED
+      {
+         static char key[] = "end marker";
+         static char comment[] = "end";
+         png_text text;
+
+         /* Use a compressed text string to test the correct interaction of text
+          * compression and IDAT compression.
+          */
+         text.compression = PNG_TEXT_COMPRESSION_zTXt;
+         text.key = key;
+         text.text = comment;
+         text.text_length = (sizeof comment)-1;
+         text.itxt_length = 0;
+         text.lang = 0;
+         text.lang_key = 0;
+
+         png_set_text(pp, pi, &text, 1);
+      }
+#endif
+
       png_write_end(pp, pi);
 
       /* And store this under the appropriate id, then clean up. */
-      store_storefile(ps, FILEID(colour_type, bit_depth, interlace_type,
-         0, 0, 0));
+      store_storefile(ps, FILEID(colour_type, bit_depth, palette_number,
+         interlace_type, 0, 0, 0));
 
       store_write_reset(ps);
    }
@@ -2175,10 +2715,19 @@ make_transform_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
 }
 
 static void
-make_standard(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
-    int PNG_CONST bdhi)
+make_transform_images(png_store *ps)
 {
-   for (; bdlo <= bdhi; ++bdlo)
+   png_byte colour_type = 0;
+   png_byte bit_depth = 0;
+   int palette_number = 0;
+
+   /* This is in case of errors. */
+   safecat(ps->test, sizeof ps->test, 0, "make standard images");
+
+   /* Use next_format to enumerate all the combinations we test, including
+    * generating multiple low bit depth palette images.
+    */
+   while (next_format(&colour_type, &bit_depth, &palette_number))
    {
       int interlace_type;
 
@@ -2187,29 +2736,14 @@ make_standard(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int bdlo,
       {
          char name[FILE_NAME_SIZE];
 
-         standard_name(name, sizeof name, 0, colour_type, bdlo, interlace_type,
-            0, 0, 0);
-         make_transform_image(ps, colour_type, DEPTH(bdlo), interlace_type,
-            name);
+         standard_name(name, sizeof name, 0, colour_type, bit_depth,
+            palette_number, interlace_type, 0, 0, 0);
+         make_transform_image(ps, colour_type, bit_depth, palette_number,
+            interlace_type, name);
       }
    }
 }
 
-static void
-make_transform_images(png_store *ps)
-{
-   /* This is in case of errors. */
-   safecat(ps->test, sizeof ps->test, 0, "make standard images");
-
-   /* Arguments are colour_type, low bit depth, high bit depth
-    */
-   make_standard(ps, 0, 0, WRITE_BDHI);
-   make_standard(ps, 2, 3, WRITE_BDHI);
-   make_standard(ps, 3, 0, 3 /*palette: max 8 bits*/);
-   make_standard(ps, 4, 3, WRITE_BDHI);
-   make_standard(ps, 6, 3, WRITE_BDHI);
-}
-
 /* The following two routines use the PNG interlace support macros from
  * png.h to interlace or deinterlace rows.
  */
@@ -2254,7 +2788,7 @@ deinterlace_row(png_bytep buffer, png_const_bytep row,
    }
 }
 
-/* Build a single row for the 'size' test images, this fills in only the
+/* Build a single row for the 'size' test images; this fills in only the
  * first bit_width bits of the sample row.
  */
 static void
@@ -2294,8 +2828,8 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
 
       /* Make a name and get an appropriate id for the store: */
       char name[FILE_NAME_SIZE];
-      PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, interlace_type,
-         w, h, do_interlace);
+      PNG_CONST png_uint_32 id = FILEID(colour_type, bit_depth, 0/*palette*/,
+         interlace_type, w, h, do_interlace);
 
       standard_name_from_id(name, sizeof name, 0, id);
       pp = set_store_for_write(ps, &pi, name);
@@ -2310,20 +2844,8 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
       png_set_IHDR(pp, pi, w, h, bit_depth, colour_type, interlace_type,
          PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
-      /* Same palette as make_transform_image - I don' think there is any
-       * benefit from using a different one (JB 20101211)
-       */
       if (colour_type == 3) /* palette */
-      {
-         unsigned int i = 0;
-         png_color pal[256];
-
-         do
-            pal[i].red = pal[i].green = pal[i].blue = (png_byte)i;
-         while(++i < 256U);
-
-         png_set_PLTE(pp, pi, pal, 256);
-      }
+         init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/);
 
       png_write_info(pp, pi);
 
@@ -2369,7 +2891,7 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type,
                png_byte tempRow[SIZE_ROWMAX];
 
                /* If do_interlace *and* the image is interlaced we
-                * need a reduced interlace row, this may be reduced
+                * need a reduced interlace row; this may be reduced
                 * to empty.
                 */
                if (do_interlace && interlace_type == PNG_INTERLACE_ADAM7)
@@ -2480,6 +3002,7 @@ standard_row(png_structp pp, png_byte std[STANDARD_ROWMAX], png_uint_32 id,
  * to ensure that they get detected - it should not be possible to write an
  * invalid image with libpng!
  */
+#ifdef PNG_WARNINGS_SUPPORTED
 static void
 sBIT0_error_fn(png_structp pp, png_infop pi)
 {
@@ -2514,6 +3037,7 @@ static PNG_CONST struct
    unsigned int    warning :1; /* the error is a warning... */
 } error_test[] =
     {
+       /* no warnings makes these errors undetectable. */
        { sBIT0_error_fn, "sBIT(0): failed to detect error", 1 },
        { sBIT_error_fn, "sBIT(too big): failed to detect error", 1 },
     };
@@ -2539,18 +3063,9 @@ make_error(png_store* volatile ps, png_byte PNG_CONST colour_type,
          interlace_type, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 
       if (colour_type == 3) /* palette */
-      {
-         unsigned int i = 0;
-         png_color pal[256];
-
-         do
-            pal[i].red = pal[i].green = pal[i].blue = (png_byte)i;
-         while(++i < 256U);
-
-         png_set_PLTE(pp, pi, pal, 256);
-      }
+         init_standard_palette(ps, pp, pi, 1U << bit_depth, 0/*do tRNS*/);
 
-      /* Time for a few errors, these are in various optional chunks, the
+      /* Time for a few errors; these are in various optional chunks, the
        * standard tests test the standard chunks pretty well.
        */
 #     define exception__prev exception_prev_1
@@ -2641,8 +3156,8 @@ make_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
          unsigned int test;
          char name[FILE_NAME_SIZE];
 
-         standard_name(name, sizeof name, 0, colour_type, bdlo, interlace_type,
-            0, 0, 0);
+         standard_name(name, sizeof name, 0, colour_type, 1<<bdlo, 0,
+            interlace_type, 0, 0, 0);
 
          for (test=0; test<(sizeof error_test)/(sizeof error_test[0]); ++test)
          {
@@ -2657,10 +3172,12 @@ make_errors(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
 
    return 1; /* keep going */
 }
+#endif
 
 static void
 perform_error_test(png_modifier *pm)
 {
+#ifdef PNG_WARNINGS_SUPPORTED /* else there are no cases that work! */
    /* Need to do this here because we just write in this test. */
    safecat(pm->this.test, sizeof pm->this.test, 0, "error test");
 
@@ -2678,6 +3195,73 @@ perform_error_test(png_modifier *pm)
 
    if (!make_errors(pm, 6, 3, WRITE_BDHI))
       return;
+#else
+   UNUSED(pm)
+#endif
+}
+
+/* This is just to validate the internal PNG formatting code - if this fails
+ * then the warning messages the library outputs will probably be garbage.
+ */
+static void
+perform_formatting_test(png_store *volatile ps)
+{
+#ifdef PNG_TIME_RFC1123_SUPPORTED
+   /* The handle into the formatting code is the RFC1123 support; this test does
+    * nothing if that is compiled out.
+    */
+   context(ps, fault);
+
+   Try
+   {
+      png_const_charp correct = "29 Aug 2079 13:53:60 +0000";
+      png_const_charp result;
+      png_structp pp;
+      png_time pt;
+
+      pp = set_store_for_write(ps, NULL, "libpng formatting test");
+
+      if (pp == NULL)
+         Throw ps;
+
+
+      /* Arbitrary settings: */
+      pt.year = 2079;
+      pt.month = 8;
+      pt.day = 29;
+      pt.hour = 13;
+      pt.minute = 53;
+      pt.second = 60; /* a leap second */
+
+      result = png_convert_to_rfc1123(pp, &pt);
+
+      if (result == NULL)
+         png_error(pp, "png_convert_to_rfc1123 failed");
+
+      if (strcmp(result, correct) != 0)
+      {
+         size_t pos = 0;
+         char msg[128];
+
+         pos = safecat(msg, sizeof msg, pos, "png_convert_to_rfc1123(");
+         pos = safecat(msg, sizeof msg, pos, correct);
+         pos = safecat(msg, sizeof msg, pos, ") returned: '");
+         pos = safecat(msg, sizeof msg, pos, result);
+         pos = safecat(msg, sizeof msg, pos, "'");
+
+         png_error(pp, msg);
+      }
+
+      store_write_reset(ps);
+   }
+
+   Catch(fault)
+   {
+      store_write_reset(fault);
+   }
+#else
+   UNUSED(ps)
+#endif
 }
 
 /* Because we want to use the same code in both the progressive reader and the
@@ -2702,16 +3286,8 @@ perform_error_test(png_modifier *pm)
  * requirement that the pointer to the first member of a structure must be the
  * same as the pointer to the structure.  This allows us to reuse standard_
  * functions in the gamma test code; something that could not be done with
- * nested funtions!
+ * nested functions!
  */
-typedef struct standard_palette_entry /* pngvalid format palette! */
-{
-   png_byte red;
-   png_byte green;
-   png_byte blue;
-   png_byte alpha;
-} standard_palette[256];
-
 typedef struct standard_display
 {
    png_store*  ps;             /* Test parameters (passed to the function) */
@@ -2730,14 +3306,16 @@ typedef struct standard_display
    png_uint_32 bit_width;      /* Width of output row in bits */
    size_t      cbRow;          /* Bytes in a row of the output image */
    int         do_interlace;   /* Do interlacing internally */
-   int         is_transparent; /* Transparecy information was present. */
+   int         is_transparent; /* Transparency information was present. */
+   int         speed;          /* Doing a speed test */
    struct
    {
       png_uint_16 red;
       png_uint_16 green;
       png_uint_16 blue;
    }           transparent;    /* The transparent color, if set. */
-   standard_palette
+   int         npalette;       /* Number of entries in the palette. */
+   store_palette
                palette;
 } standard_display;
 
@@ -2748,8 +3326,11 @@ standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id,
    dp->ps = ps;
    dp->colour_type = COL_FROM_ID(id);
    dp->bit_depth = DEPTH_FROM_ID(id);
-   dp->alpha_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT =
-      dp->bit_depth;
+   if (dp->colour_type == 3)
+      dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT = 8;
+   else
+      dp->red_sBIT = dp->blue_sBIT = dp->green_sBIT = dp->alpha_sBIT =
+         dp->bit_depth;
    dp->interlace_type = INTERLACE_FROM_ID(id);
    dp->id = id;
    /* All the rest are filled in after the read_info: */
@@ -2761,48 +3342,98 @@ standard_display_init(standard_display *dp, png_store* ps, png_uint_32 id,
    dp->cbRow = 0;
    dp->do_interlace = do_interlace;
    dp->is_transparent = 0;
+   dp->speed = ps->speed;
+   dp->npalette = 0;
    /* Preset the transparent color to black: */
    memset(&dp->transparent, 0, sizeof dp->transparent);
    /* Preset the palette to full intensity/opaque througout: */
    memset(dp->palette, 0xff, sizeof dp->palette);
+}
+
+/* Initialize the palette fields - this must be done later because the palette
+ * comes from the particular png_store_file that is selected.
+ */
+static void
+standard_palette_init(standard_display *dp)
+{
+   store_palette_entry *palette = store_current_palette(dp->ps, &dp->npalette);
+
+   /* The remaining entries remain white/opaque. */
+   if (dp->npalette > 0)
+   {
+      int i = dp->npalette;
+      memcpy(dp->palette, palette, i * sizeof *palette);
+
+      /* Check for a non-opaque palette entry: */
+      while (--i >= 0)
+         if (palette[i].alpha < 255)
+            break;
 
+#     ifdef __GNUC__
+         /* GCC can't handle the more obviously optimizable version. */
+         if (i >= 0)
+            dp->is_transparent = 1;
+         else
+            dp->is_transparent = 0;
+#     else
+         dp->is_transparent = (i >= 0);
+#     endif
+   }
 }
 
-/* Call this only if the colour type is 3 - PNG_COLOR_TYPE_PALETTE - otherwise
- * it will png_error out.  The API returns true if tRNS information was
- * present.
+/* Utility to read the palette from the PNG file and convert it into
+ * store_palette format.  This returns 1 if there is any transparency in the
+ * palette (it does not check for a transparent colour in the non-palette case.)
  */
 static int
-standard_palette_init(standard_palette palette, png_structp pp, png_infop pi)
+read_palette(store_palette palette, int *npalette, png_structp pp, png_infop pi)
 {
    png_colorp pal;
    png_bytep trans_alpha;
    int num;
 
    pal = 0;
-   num = -1;
-   if (png_get_PLTE(pp, pi, &pal, &num) & PNG_INFO_PLTE)
+   *npalette = -1;
+
+   if (png_get_PLTE(pp, pi, &pal, npalette) & PNG_INFO_PLTE)
    {
-      int i;
+      int i = *npalette;
 
-      for (i=0; i<num; ++i)
+      if (i <= 0 || i > 256)
+         png_error(pp, "validate: invalid PLTE count");
+
+      while (--i >= 0)
       {
          palette[i].red = pal[i].red;
          palette[i].green = pal[i].green;
          palette[i].blue = pal[i].blue;
       }
 
-      /* Mark the remainder of the entries with a flag value: */
-      for (; i<256; ++i)
-         palette[i].red = palette[i].green = palette[i].blue = 126;
+      /* Mark the remainder of the entries with a flag value (other than
+       * white/opaque which is the flag value stored above.)
+       */
+      memset(palette + *npalette, 126, (256-*npalette) * sizeof *palette);
    }
 
    else /* !png_get_PLTE */
-      png_error(pp, "validate: missing PLTE with color type 3");
+   {
+      if (*npalette != (-1))
+         png_error(pp, "validate: invalid PLTE result");
+      /* But there is no palette, so record this: */
+      *npalette = 0;
+      memset(palette, 113, sizeof palette);
+   }
 
    trans_alpha = 0;
-   num = -1;
-   if (png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS)
+   num = 2; /* force error below */
+   if ((png_get_tRNS(pp, pi, &trans_alpha, &num, 0) & PNG_INFO_tRNS) != 0 &&
+      (trans_alpha != NULL || num != 1/*returns 1 for a transparent color*/) &&
+      /* Oops, if a palette tRNS gets expanded png_read_update_info (at least so
+       * far as 1.5.4) does not zap the trans_alpha pointer, only num_trans, so
+       * in the above call we get a success, we get a pointer (who knows what
+       * to) and we get num_trans == 0:
+       */
+      !(trans_alpha != NULL && num == 0)) /* TODO: fix this in libpng. */
    {
       int i;
 
@@ -2812,30 +3443,72 @@ standard_palette_init(standard_palette palette, png_structp pp, png_infop pi)
        * actually been filled in!  Note that if the app were to pass the
        * last, png_color_16p, variable too it couldn't rely on this.
        */
-      if (trans_alpha == 0 || num <= 0 || num > 256)
+      if (trans_alpha == NULL || num <= 0 || num > 256 || num > *npalette)
          png_error(pp, "validate: unexpected png_get_tRNS (palette) result");
 
       for (i=0; i<num; ++i)
          palette[i].alpha = trans_alpha[i];
 
-      for (; i<256; ++i)
+      for (num=*npalette; i<num; ++i)
          palette[i].alpha = 255;
 
+      for (; i<256; ++i)
+         palette[i].alpha = 33; /* flag value */
+
       return 1; /* transparency */
    }
 
    else
    {
-      /* No transparency - just set the alpha channel to opaque. */
+      /* No palette transparency - just set the alpha channel to opaque. */
       int i;
 
-      for (i=0; i<256; ++i)
+      for (i=0, num=*npalette; i<num; ++i)
          palette[i].alpha = 255;
 
+      for (; i<256; ++i)
+         palette[i].alpha = 55; /* flag value */
+
       return 0; /* no transparency */
    }
 }
 
+/* Utility to validate the palette if it should not have changed (the
+ * non-transform case).
+ */
+static void
+standard_palette_validate(standard_display *dp, png_structp pp, png_infop pi)
+{
+   int npalette;
+   store_palette palette;
+
+   if (read_palette(palette, &npalette, pp, pi) != dp->is_transparent)
+      png_error(pp, "validate: palette transparency changed");
+
+   if (npalette != dp->npalette)
+   {
+      size_t pos = 0;
+      char msg[64];
+
+      pos = safecat(msg, sizeof msg, pos, "validate: palette size changed: ");
+      pos = safecatn(msg, sizeof msg, pos, dp->npalette);
+      pos = safecat(msg, sizeof msg, pos, " -> ");
+      pos = safecatn(msg, sizeof msg, pos, npalette);
+      png_error(pp, msg);
+   }
+
+   {
+      int i = npalette; /* npalette is aliased */
+
+      while (--i >= 0)
+         if (palette[i].red != dp->palette[i].red ||
+            palette[i].green != dp->palette[i].green ||
+            palette[i].blue != dp->palette[i].blue ||
+            palette[i].alpha != dp->palette[i].alpha)
+            png_error(pp, "validate: PLTE or tRNS chunk changed");
+   }
+}
+
 /* By passing a 'standard_display' the progressive callbacks can be used
  * directly by the sequential code, the functions suffixed "_imp" are the
  * implementations, the functions without the suffix are the callbacks.
@@ -2935,23 +3608,15 @@ standard_info_part1(standard_display *dp, png_structp pp, png_infop pi)
    if (png_get_rowbytes(pp, pi) != standard_rowsize(pp, dp->id))
       png_error(pp, "validate: row size changed");
 
-   /* The palette is never read for non-palette images, even though it is valid
-    * - this could be changed.
+   /* Validate the colour type 3 palette (this can be present on other color
+    * types.)
     */
-   if (dp->colour_type == 3) /* palette */
-   {
-      int i;
-
-      dp->is_transparent = standard_palette_init(dp->palette, pp, pi);
+   standard_palette_validate(dp, pp, pi);
 
-      /* And validate the result. */
-      for (i=0; i<256; ++i)
-         if (dp->palette[i].red != i || dp->palette[i].green != i ||
-            dp->palette[i].blue != i)
-            png_error(pp, "validate: color type 3 PLTE chunk changed");
-   }
-
-   /* In any case always check for a tranparent color: */
+   /* In any case always check for a tranparent color (notice that the
+    * colour type 3 case must not give a successful return on the get_tRNS call
+    * with these arguments!)
+    */
    {
       png_color_16p trans_color = 0;
 
@@ -3020,7 +3685,7 @@ standard_info_part2(standard_display *dp, png_structp pp, png_infop pi,
       png_error(pp, "bad png_get_rowbytes calculation");
 
    /* Then ensure there is enough space for the output image(s). */
-   store_ensure_image(dp->ps, pp, nImages * dp->cbRow * dp->h);
+   store_ensure_image(dp->ps, pp, nImages, dp->cbRow, dp->h);
 }
 
 static void
@@ -3073,12 +3738,14 @@ progressive_row(png_structp pp, png_bytep new_row, png_uint_32 y, int pass)
        */
       if (dp->do_interlace && dp->interlace_type == PNG_INTERLACE_ADAM7)
       {
+#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
          /* Use this opportunity to validate the png 'current' APIs: */
          if (y != png_get_current_row_number(pp))
             png_error(pp, "png_get_current_row_number is broken");
 
          if (pass != png_get_current_pass_number(pp))
             png_error(pp, "png_get_current_pass_number is broken");
+#endif
 
          y = PNG_ROW_FROM_PASS_ROW(y, pass);
       }
@@ -3087,7 +3754,7 @@ progressive_row(png_structp pp, png_bytep new_row, png_uint_32 y, int pass)
       if (y >= dp->h)
          png_error(pp, "invalid y to progressive row callback");
 
-      row = dp->ps->image + y * dp->cbRow;
+      row = store_image_row(dp->ps, pp, 0, y);
 
       /* Combine the new row into the old: */
       if (dp->do_interlace)
@@ -3107,22 +3774,20 @@ progressive_row(png_structp pp, png_bytep new_row, png_uint_32 y, int pass)
 
 static void
 sequential_row(standard_display *dp, png_structp pp, png_infop pi,
-    PNG_CONST png_bytep pImage, PNG_CONST png_bytep pDisplay)
+    PNG_CONST int iImage, PNG_CONST int iDisplay)
 {
    PNG_CONST int         npasses = dp->npasses;
    PNG_CONST int         do_interlace = dp->do_interlace &&
       dp->interlace_type == PNG_INTERLACE_ADAM7;
    PNG_CONST png_uint_32 height = standard_height(pp, dp->id);
    PNG_CONST png_uint_32 width = standard_width(pp, dp->id);
-   PNG_CONST size_t      cbRow = dp->cbRow;
+   PNG_CONST png_store*  ps = dp->ps;
    int pass;
 
    for (pass=0; pass<npasses; ++pass)
    {
       png_uint_32 y;
       png_uint_32 wPass = PNG_PASS_COLS(width, pass);
-      png_bytep pRow1 = pImage;
-      png_bytep pRow2 = pDisplay;
 
       for (y=0; y<height; ++y)
       {
@@ -3147,21 +3812,19 @@ sequential_row(standard_display *dp, png_structp pp, png_infop pi,
 
                png_read_row(pp, row, display);
 
-               if (pRow1 != NULL)
-                  deinterlace_row(pRow1, row, dp->pixel_size, dp->w, pass);
+               if (iImage >= 0)
+                  deinterlace_row(store_image_row(ps, pp, iImage, y), row,
+                     dp->pixel_size, dp->w, pass);
 
-               if (pRow2 != NULL)
-                  deinterlace_row(pRow2, display, dp->pixel_size, dp->w, pass);
+               if (iDisplay >= 0)
+                  deinterlace_row(store_image_row(ps, pp, iDisplay, y), display,
+                     dp->pixel_size, dp->w, pass);
             }
          }
          else
-            png_read_row(pp, pRow1, pRow2);
-
-         if (pRow1 != NULL)
-            pRow1 += cbRow;
-
-         if (pRow2 != NULL)
-            pRow2 += cbRow;
+            png_read_row(pp,
+               iImage >= 0 ? store_image_row(ps, pp, iImage, y) : NULL,
+               iDisplay >= 0 ? store_image_row(ps, pp, iDisplay, y) : NULL);
       }
    }
 
@@ -3172,8 +3835,8 @@ sequential_row(standard_display *dp, png_structp pp, png_infop pi,
 }
 
 static void
-standard_row_validate(standard_display *dp, png_structp pp, png_const_bytep row,
-   png_const_bytep display, png_uint_32 y)
+standard_row_validate(standard_display *dp, png_structp pp,
+   int iImage, int iDisplay, png_uint_32 y)
 {
    png_byte std[STANDARD_ROWMAX];
 
@@ -3191,7 +3854,8 @@ standard_row_validate(standard_display *dp, png_structp pp, png_const_bytep row,
     * row bytes are always trashed, so we always do a pixel_cmp here even though
     * a memcmp of all cbRow bytes will succeed for the sequential reader.
     */
-   if (row != NULL && pixel_cmp(std, row, dp->bit_width) != 0)
+   if (iImage >= 0 && pixel_cmp(std, store_image_row(dp->ps, pp, iImage, y),
+      dp->bit_width) != 0)
    {
       char msg[64];
       sprintf(msg, "PNG image row %d changed", y);
@@ -3202,7 +3866,8 @@ standard_row_validate(standard_display *dp, png_structp pp, png_const_bytep row,
     * byte at the end of the row if the row is not an exact multiple
     * of 8 bits wide.
     */
-   if (display != NULL && pixel_cmp(std, display, dp->bit_width) != 0)
+   if (iDisplay >= 0 && pixel_cmp(std, store_image_row(dp->ps, pp, iDisplay, y),
+      dp->bit_width) != 0)
    {
       char msg[64];
       sprintf(msg, "display row %d changed", y);
@@ -3211,21 +3876,19 @@ standard_row_validate(standard_display *dp, png_structp pp, png_const_bytep row,
 }
 
 static void
-standard_image_validate(standard_display *dp, png_structp pp,
-   png_const_bytep pImage, png_const_bytep pDisplay)
+standard_image_validate(standard_display *dp, png_structp pp, int iImage,
+    int iDisplay)
 {
    png_uint_32 y;
 
-   for (y=0; y<dp->h; ++y)
-   {
-      standard_row_validate(dp, pp, pImage, pDisplay, y);
+   if (iImage >= 0)
+      store_image_check(dp->ps, pp, iImage);
 
-      if (pImage != NULL)
-         pImage += dp->cbRow;
+   if (iDisplay >= 0)
+      store_image_check(dp->ps, pp, iDisplay);
 
-      if (pDisplay != NULL)
-         pDisplay += dp->cbRow;
-   }
+   for (y=0; y<dp->h; ++y)
+      standard_row_validate(dp, pp, iImage, iDisplay, y);
 
    /* This avoids false positives if the validation code is never called! */
    dp->ps->validated = 1;
@@ -3241,7 +3904,7 @@ standard_end(png_structp pp, png_infop pi)
    /* Validate the image - progressive reading only produces one variant for
     * interlaced images.
     */
-   standard_image_validate(dp, pp, dp->ps->image, NULL);
+   standard_image_validate(dp, pp, 0, -1);
 }
 
 /* A single test run checking the standard image to ensure it is not damaged. */
@@ -3274,6 +3937,9 @@ standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id,
             "pngvalid sequential deinterlacer") : (d.ps->progressive ?
                "progressive reader" : "sequential reader"));
 
+      /* Initialize the palette correctly from the png_store_file. */
+      standard_palette_init(&d);
+
       /* Introduce the correct read function. */
       if (d.ps->progressive)
       {
@@ -3301,15 +3967,13 @@ standard_test(png_store* PNG_CONST psIn, png_uint_32 PNG_CONST id,
           * values.
           */
          {
-            PNG_CONST png_bytep pImage = d.ps->image;
-            PNG_CONST png_bytep pDisplay = pImage + d.cbRow * d.h;
-
-            sequential_row(&d, pp, pi, pImage, pDisplay);
+            sequential_row(&d, pp, pi, 0, 1);
 
             /* After the last pass loop over the rows again to check that the
              * image is correct.
              */
-            standard_image_validate(&d, pp, pImage, pDisplay);
+            if (!d.speed)
+               standard_image_validate(&d, pp, 0, 1);
          }
       }
 
@@ -3338,7 +4002,7 @@ test_standard(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
       for (interlace_type = PNG_INTERLACE_NONE;
            interlace_type < PNG_INTERLACE_LAST; ++interlace_type)
       {
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             interlace_type, 0, 0, 0), 0/*do_interlace*/);
 
          if (fail(pm))
@@ -3397,25 +4061,25 @@ test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
           * validates the write side of libpng.  There are four possibilities
           * to validate.
           */
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/);
 
          if (fail(pm))
             return 0;
 
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/);
 
          if (fail(pm))
             return 0;
 
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/);
 
          if (fail(pm))
             return 0;
 
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/);
 
          if (fail(pm))
@@ -3425,13 +4089,13 @@ test_size(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
           * in the progressive case this does actually make a difference
           * to the code used in the non-interlaced case too.
           */
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/);
 
          if (fail(pm))
             return 0;
 
-         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
+         standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
             PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/);
 
          if (fail(pm))
@@ -3471,6 +4135,7 @@ perform_size_test(png_modifier *pm)
 
 
 /******************************* TRANSFORM TESTS ******************************/
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 /* A set of tests to validate libpng image transforms.  The possibilities here
  * are legion because the transforms can be combined in a combinatorial
  * fashion.  To deal with this some measure of restraint is required, otherwise
@@ -3533,7 +4198,7 @@ image_pixel_setf(image_pixel *this, unsigned int max)
  */
 static void
 image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
-    png_byte bit_depth, png_uint_32 x, standard_palette palette)
+    png_byte bit_depth, png_uint_32 x, store_palette palette)
 {
    PNG_CONST png_byte sample_depth = (png_byte)(colour_type ==
       PNG_COLOR_TYPE_PALETTE ? 8 : bit_depth);
@@ -3594,44 +4259,33 @@ image_pixel_init(image_pixel *this, png_const_bytep row, png_byte colour_type,
 }
 
 /* Convert a palette image to an rgb image.  This necessarily converts the tRNS
- * chunk at the same time, because the tRNS will be in palette form.
+ * chunk at the same time, because the tRNS will be in palette form.  The way
+ * palette validation works means that the original palette is never updated,
+ * instead the image_pixel value from the row contains the RGB of the
+ * corresponding palette entry and *this* is updated.  Consequently this routine
+ * only needs to change the colour type information.
  */
 static void
-image_pixel_convert_PLTE(image_pixel *this, const standard_display *display)
+image_pixel_convert_PLTE(image_pixel *this)
 {
    if (this->colour_type == PNG_COLOR_TYPE_PALETTE)
    {
-      PNG_CONST unsigned int i = this->palette_index;
-
-      this->bit_depth = this->sample_depth;
-      this->red = display->palette[i].red;
-      this->green = display->palette[i].green;
-      this->blue = display->palette[i].blue;
-      this->red_sBIT = display->red_sBIT;
-      this->green_sBIT = display->green_sBIT;
-      this->blue_sBIT = display->blue_sBIT;
-
       if (this->have_tRNS)
       {
-         this->alpha = display->palette[i].alpha;
          this->colour_type = PNG_COLOR_TYPE_RGB_ALPHA;
          this->have_tRNS = 0;
       }
       else
-      {
-         this->alpha = 255;
          this->colour_type = PNG_COLOR_TYPE_RGB;
-      }
-      this->alpha_sBIT = 8;
 
-      /* And regenerate the scaled values and all the errors, which are now set
-       * back to the initial values.
+      /* The bit depth of the row changes at this point too (notice that this is
+       * the row format, not the sample depth, which is separate.)
        */
-      image_pixel_setf(this, 255);
+      this->bit_depth = 8;
    }
 }
 
-/* Add an alpha channel, this will glom in the tRNS information because tRNS is
+/* Add an alpha channel; this will import the tRNS information because tRNS is
  * not valid in an alpha image.  The bit depth will invariably be set to at
  * least 8.  Palette images will be converted to alpha (using the above API).
  */
@@ -3639,7 +4293,7 @@ static void
 image_pixel_add_alpha(image_pixel *this, const standard_display *display)
 {
    if (this->colour_type == PNG_COLOR_TYPE_PALETTE)
-      image_pixel_convert_PLTE(this, display);
+      image_pixel_convert_PLTE(this);
 
    if ((this->colour_type & PNG_COLOR_MASK_ALPHA) == 0)
    {
@@ -3757,6 +4411,10 @@ typedef struct transform_display
    /* Local variables */
    png_byte output_colour_type;
    png_byte output_bit_depth;
+
+   /* Variables for the individual transforms. */
+   /* png_set_background */
+   image_pixel background_colour;
 } transform_display;
 
 /* Two functions to end the list: */
@@ -4005,17 +4663,19 @@ transform_info(png_structp pp, png_infop pi)
 static void
 transform_range_check(png_structp pp, unsigned int r, unsigned int g,
    unsigned int b, unsigned int a, unsigned int in_digitized, double in,
-   unsigned int out, png_byte sample_depth, double err, PNG_CONST char *name)
+   unsigned int out, png_byte sample_depth, double err, PNG_CONST char *name,
+   double digitization_error)
 {
    /* Compare the scaled, digitzed, values of our local calculation (in+-err)
     * with the digitized values libpng produced;  'sample_depth' is the actual
     * digitization depth of the libpng output colors (the bit depth except for
-    * palette images where it is always 8.)
+    * palette images where it is always 8.)  The check on 'err' is to detect
+    * internal errors in pngvalid itself (the threshold is about 1/255.)
     */
    unsigned int max = (1U<<sample_depth)-1;
-   double in_min = ceil((in-err)*max - .5);
-   double in_max = floor((in+err)*max + .5);
-   if (!(out >= in_min && out <= in_max))
+   double in_min = ceil((in-err)*max - digitization_error);
+   double in_max = floor((in+err)*max + digitization_error);
+   if (err > 4E-3 || !(out >= in_min && out <= in_max))
    {
       char message[256];
       size_t pos;
@@ -4044,15 +4704,14 @@ transform_range_check(png_structp pp, unsigned int r, unsigned int g,
 }
 
 static void
-transform_image_validate(transform_display *dp, png_structp pp, png_infop pi,
-    png_const_bytep pRow)
+transform_image_validate(transform_display *dp, png_structp pp, png_infop pi)
 {
    /* Constants for the loop below: */
+   PNG_CONST png_store* PNG_CONST ps = dp->this.ps;
    PNG_CONST png_byte in_ct = dp->this.colour_type;
    PNG_CONST png_byte in_bd = dp->this.bit_depth;
    PNG_CONST png_uint_32 w = dp->this.w;
    PNG_CONST png_uint_32 h = dp->this.h;
-   PNG_CONST size_t cbRow = dp->this.cbRow;
    PNG_CONST png_byte out_ct = dp->output_colour_type;
    PNG_CONST png_byte out_bd = dp->output_bit_depth;
    PNG_CONST png_byte sample_depth = (png_byte)(out_ct ==
@@ -4062,22 +4721,63 @@ transform_image_validate(transform_display *dp, png_structp pp, png_infop pi,
    PNG_CONST png_byte blue_sBIT = dp->this.blue_sBIT;
    PNG_CONST png_byte alpha_sBIT = dp->this.alpha_sBIT;
    PNG_CONST int have_tRNS = dp->this.is_transparent;
+   double digitization_error;
 
-   standard_palette out_palette;
+   store_palette out_palette;
    png_uint_32 y;
 
    UNUSED(pi)
 
+   /* Check for row overwrite errors */
+   store_image_check(dp->this.ps, pp, 0);
+
    /* Read the palette corresponding to the output if the output colour type
     * indicates a palette, othewise set out_palette to garbage.
     */
    if (out_ct == PNG_COLOR_TYPE_PALETTE)
-      (void)standard_palette_init(out_palette, pp, pi);
+   {
+      /* Validate that the palette count itself has not changed - this is not
+       * expected.
+       */
+      int npalette = (-1);
+
+      (void)read_palette(out_palette, &npalette, pp, pi);
+      if (npalette != dp->this.npalette)
+         png_error(pp, "unexpected change in palette size");
+
+      digitization_error = .5;
+   }
    else
+   {
+      png_byte in_sample_depth;
+
       memset(out_palette, 0x5e, sizeof out_palette);
 
-   for (y=0; y<h; ++y, pRow += cbRow)
+      /* assume-8-bit-calculations means assume that if the input has 8 bit
+       * (or less) samples and the output has 16 bit samples the calculations
+       * will be done with 8 bit precision, not 16.
+       *
+       * TODO: fix this in libpng; png_set_expand_16 should cause 16 bit
+       * calculations to be used throughout.
+       */
+      if (in_ct == PNG_COLOR_TYPE_PALETTE || in_bd < 16)
+         in_sample_depth = 8;
+      else
+         in_sample_depth = in_bd;
+
+      if (sample_depth != 16 || in_sample_depth > 8 ||
+         !dp->pm->calculations_use_input_precision)
+         digitization_error = .5;
+
+      /* Else errors are at 8 bit precision, scale .5 in 8 bits to the 16 bits:
+       */
+      else
+         digitization_error = .5 * 257;
+   }
+
+   for (y=0; y<h; ++y)
    {
+      png_const_bytep PNG_CONST pRow = store_image_row(ps, pp, 0, y);
       png_uint_32 x;
 
       /* The original, standard, row pre-transforms. */
@@ -4130,24 +4830,26 @@ transform_image_validate(transform_display *dp, png_structp pp, png_infop pi,
           */
          if (in_pixel.red != out_pixel.red)
             transform_range_check(pp, r, g, b, a, in_pixel.red, in_pixel.redf,
-               out_pixel.red, sample_depth, in_pixel.rede, "red/gray");
+               out_pixel.red, sample_depth, in_pixel.rede, "red/gray",
+               digitization_error);
 
          if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 &&
             in_pixel.green != out_pixel.green)
             transform_range_check(pp, r, g, b, a, in_pixel.green,
                in_pixel.greenf, out_pixel.green, sample_depth, in_pixel.greene,
-               "green");
+               "green", digitization_error);
 
          if ((out_ct & PNG_COLOR_MASK_COLOR) != 0 &&
             in_pixel.blue != out_pixel.blue)
             transform_range_check(pp, r, g, b, a, in_pixel.blue, in_pixel.bluef,
-               out_pixel.blue, sample_depth, in_pixel.bluee, "blue");
+               out_pixel.blue, sample_depth, in_pixel.bluee, "blue",
+               digitization_error);
 
          if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0 &&
             in_pixel.alpha != out_pixel.alpha)
             transform_range_check(pp, r, g, b, a, in_pixel.alpha,
                in_pixel.alphaf, out_pixel.alpha, sample_depth, in_pixel.alphae,
-               "alpha");
+               "alpha", digitization_error);
       } /* pixel (x) loop */
    } /* row (y) loop */
 
@@ -4160,7 +4862,7 @@ transform_end(png_structp pp, png_infop pi)
 {
    transform_display *dp = png_get_progressive_ptr(pp);
 
-   transform_image_validate(dp, pp, pi, dp->this.ps->image);
+   transform_image_validate(dp, pp, pi);
 }
 
 /* A single test run. */
@@ -4178,8 +4880,9 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
       png_structp pp;
       png_infop pi;
 
-      /* Get a png_struct for writing the image. */
+      /* Get a png_struct for reading the image. */
       pp = set_modifier_for_read(d.pm, &pi, d.this.id, name);
+      standard_palette_init(&d.this);
 
 #     if 0
          /* Logging (debugging only) */
@@ -4214,9 +4917,10 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
          /* Process the 'info' requirements. Only one image is generated */
          transform_info_imp(&d, pp, pi);
 
-         sequential_row(&d.this, pp, pi, NULL, d.this.ps->image);
+         sequential_row(&d.this, pp, pi, -1, 0);
 
-         transform_image_validate(&d, pp, pi, d.this.ps->image);
+         if (!d.this.speed)
+            transform_image_validate(&d, pp, pi);
       }
 
       modifier_reset(d.pm);
@@ -4228,12 +4932,12 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn,
 
 /* The transforms: */
 #define ITSTRUCT(name) image_transform_##name
-#define IT(name,prev)\
+#define IT(name)\
 static image_transform ITSTRUCT(name) =\
 {\
    #name,\
    1, /*enable*/\
-   &ITSTRUCT(prev), /*list*/\
+   &PT, /*list*/\
    0, /*global_use*/\
    0, /*local_use*/\
    0, /*next*/\
@@ -4241,6 +4945,7 @@ static image_transform ITSTRUCT(name) =\
    image_transform_png_set_##name##_mod,\
    image_transform_png_set_##name##_add\
 }
+#define PT ITSTRUCT(end) /* stores the previous transform */
 
 /* To save code: */
 static int
@@ -4256,6 +4961,7 @@ image_transform_default_add(image_transform *this,
    return 1;
 }
 
+#ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_palette_to_rgb */
 static void
 image_transform_png_set_palette_to_rgb_set(PNG_CONST image_transform *this,
@@ -4270,7 +4976,7 @@ image_transform_png_set_palette_to_rgb_mod(PNG_CONST image_transform *this,
     image_pixel *that, png_structp pp, PNG_CONST transform_display *display)
 {
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-      image_pixel_convert_PLTE(that, &display->this);
+      image_pixel_convert_PLTE(that);
 
    this->next->mod(this->next, that, pp, display);
 }
@@ -4287,9 +4993,12 @@ image_transform_png_set_palette_to_rgb_add(image_transform *this,
    return colour_type == PNG_COLOR_TYPE_PALETTE;
 }
 
-IT(palette_to_rgb, end);
-
+IT(palette_to_rgb);
+#undef PT
+#define PT ITSTRUCT(palette_to_rgb)
+#endif /* PNG_READ_EXPAND_SUPPORTED */
 
+#ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_tRNS_to_alpha */
 static void
 image_transform_png_set_tRNS_to_alpha_set(PNG_CONST image_transform *this,
@@ -4305,10 +5014,10 @@ image_transform_png_set_tRNS_to_alpha_mod(PNG_CONST image_transform *this,
 {
    /* LIBPNG BUG: this always forces palette images to RGB. */
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-      image_pixel_convert_PLTE(that, &display->this);
+      image_pixel_convert_PLTE(that);
 
    /* This effectively does an 'expand' only if there is some transparency to
-    * covert to an alpha channel.
+    * convert to an alpha channel.
     */
    if (that->have_tRNS)
       image_pixel_add_alpha(that, &display->this);
@@ -4341,8 +5050,12 @@ image_transform_png_set_tRNS_to_alpha_add(image_transform *this,
    return (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
 }
 
-IT(tRNS_to_alpha,palette_to_rgb);
+IT(tRNS_to_alpha);
+#undef PT
+#define PT ITSTRUCT(tRNS_to_alpha)
+#endif /* PNG_READ_EXPAND_SUPPORTED */
 
+#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 /* png_set_gray_to_rgb */
 static void
 image_transform_png_set_gray_to_rgb_set(PNG_CONST image_transform *this,
@@ -4395,8 +5108,12 @@ image_transform_png_set_gray_to_rgb_add(image_transform *this,
    return (colour_type & PNG_COLOR_MASK_COLOR) == 0;
 }
 
-IT(gray_to_rgb,tRNS_to_alpha);
+IT(gray_to_rgb);
+#undef PT
+#define PT ITSTRUCT(gray_to_rgb)
+#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */
 
+#ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_expand */
 static void
 image_transform_png_set_expand_set(PNG_CONST image_transform *this,
@@ -4412,7 +5129,7 @@ image_transform_png_set_expand_mod(PNG_CONST image_transform *this,
 {
    /* The general expand case depends on what the colour type is: */
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-      image_pixel_convert_PLTE(that, &display->this);
+      image_pixel_convert_PLTE(that);
    else if (that->bit_depth < 8) /* grayscale */
       that->sample_depth = that->bit_depth = 8;
 
@@ -4437,8 +5154,12 @@ image_transform_png_set_expand_add(image_transform *this,
    return (colour_type & PNG_COLOR_MASK_ALPHA) == 0;
 }
 
-IT(expand,gray_to_rgb);
+IT(expand);
+#undef PT
+#define PT ITSTRUCT(expand)
+#endif /* PNG_READ_EXPAND_SUPPORTED */
 
+#ifdef PNG_READ_EXPAND_SUPPORTED
 /* png_set_expand_gray_1_2_4_to_8
  * LIBPNG BUG: this just does an 'expand'
  */
@@ -4467,7 +5188,12 @@ image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this,
       bit_depth);
 }
 
-IT(expand_gray_1_2_4_to_8, expand);
+IT(expand_gray_1_2_4_to_8);
+#undef PT
+#define PT ITSTRUCT(expand_gray_1_2_4_to_8)
+#endif /* PNG_READ_EXPAND_SUPPORTED */
+
+#ifdef PNG_READ_EXPAND_16_SUPPORTED
 /* png_set_expand_16 */
 static void
 image_transform_png_set_expand_16_set(PNG_CONST image_transform *this,
@@ -4485,7 +5211,7 @@ image_transform_png_set_expand_16_mod(PNG_CONST image_transform *this,
     * causing 'expand' to happen.
     */
    if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-      image_pixel_convert_PLTE(that, &display->this);
+      image_pixel_convert_PLTE(that);
 
    if (that->have_tRNS)
       image_pixel_add_alpha(that, &display->this);
@@ -4509,8 +5235,55 @@ image_transform_png_set_expand_16_add(image_transform *this,
    return bit_depth < 16;
 }
 
-IT(expand_16, expand_gray_1_2_4_to_8);
+IT(expand_16);
+#undef PT
+#define PT ITSTRUCT(expand_16)
+#endif /* PNG_READ_EXPAND_16_SUPPORTED */
+
+#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED  /* API added in 1.5.4 */
+/* png_set_scale_16 */
+static void
+image_transform_png_set_scale_16_set(PNG_CONST image_transform *this,
+    transform_display *that, png_structp pp, png_infop pi)
+{
+   png_set_scale_16(pp);
+   this->next->set(this->next, that, pp, pi);
+}
+
+static void
+image_transform_png_set_scale_16_mod(PNG_CONST image_transform *this,
+    image_pixel *that, png_structp pp, PNG_CONST transform_display *display)
+{
+   if (that->bit_depth == 16)
+   {
+      that->sample_depth = that->bit_depth = 8;
+      if (that->red_sBIT > 8) that->red_sBIT = 8;
+      if (that->green_sBIT > 8) that->green_sBIT = 8;
+      if (that->blue_sBIT > 8) that->blue_sBIT = 8;
+      if (that->alpha_sBIT > 8) that->alpha_sBIT = 8;
+   }
+
+   this->next->mod(this->next, that, pp, display);
+}
+
+static int
+image_transform_png_set_scale_16_add(image_transform *this,
+    PNG_CONST image_transform **that, png_byte colour_type, png_byte bit_depth)
+{
+   UNUSED(colour_type)
+
+   this->next = *that;
+   *that = this;
+
+   return bit_depth > 8;
+}
+
+IT(scale_16);
+#undef PT
+#define PT ITSTRUCT(scale_16)
+#endif /* PNG_READ_SCALE_16_TO_8_SUPPORTED (1.5.4 on) */
 
+#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */
 /* png_set_strip_16 */
 static void
 image_transform_png_set_strip_16_set(PNG_CONST image_transform *this,
@@ -4532,9 +5305,19 @@ image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this,
       if (that->blue_sBIT > 8) that->blue_sBIT = 8;
       if (that->alpha_sBIT > 8) that->alpha_sBIT = 8;
 
-#     ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
-         /* The strip 16 algoirithm drops the low 8 bits rather than calculating
+      /* Prior to 1.5.4 png_set_strip_16 would use an 'accurate' method if this
+       * configuration option is set.  From 1.5.4 the flag is never set and the
+       * 'scale' API (above) must be used.
+       */
+#     ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED
+#        if PNG_LIBPNG_VER >= 10504
+#           error PNG_READ_ACCURATE_SCALE should not be set
+#        endif
+
+         /* The strip 16 algorithm drops the low 8 bits rather than calculating
           * 1/257, so we need to adjust the permitted errors appropriately:
+          * Notice that this is only relevant prior to the addition of the
+          * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!)
           */
          {
             PNG_CONST double d = (255-128.5)/65535;
@@ -4561,8 +5344,12 @@ image_transform_png_set_strip_16_add(image_transform *this,
    return bit_depth > 8;
 }
 
-IT(strip_16, expand_16);
+IT(strip_16);
+#undef PT
+#define PT ITSTRUCT(strip_16)
+#endif /* PNG_READ_16_TO_8_SUPPORTED */
 
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 /* png_set_strip_alpha */
 static void
 image_transform_png_set_strip_alpha_set(PNG_CONST image_transform *this,
@@ -4583,7 +5370,6 @@ image_transform_png_set_strip_alpha_mod(PNG_CONST image_transform *this,
 
    that->have_tRNS = 0;
    that->alphaf = 1;
-   that->alphae = 0;
 
    this->next->mod(this->next, that, pp, display);
 }
@@ -4600,8 +5386,12 @@ image_transform_png_set_strip_alpha_add(image_transform *this,
    return (colour_type & PNG_COLOR_MASK_ALPHA) != 0;
 }
 
-IT(strip_alpha,strip_16);
+IT(strip_alpha);
+#undef PT
+#define PT ITSTRUCT(strip_alpha)
+#endif /* PNG_READ_STRIP_ALPHA_SUPPORTED */
 
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 /* png_set_rgb_to_gray(png_structp, int err_action, double red, double green)
  * png_set_rgb_to_gray_fixed(png_structp, int err_action, png_fixed_point red,
  *    png_fixed_point green)
@@ -4639,7 +5429,7 @@ image_transform_png_set_rgb_to_gray_mod(PNG_CONST image_transform *this,
    if ((that->colour_type & PNG_COLOR_MASK_COLOR) != 0)
    {
       if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
-         image_pixel_convert_PLTE(that, &display->this);
+         image_pixel_convert_PLTE(that);
 
       /* Image now has RGB channels... */
       that->bluef = that->greenf = that->redf = (that->redf * 6968 +
@@ -4677,8 +5467,12 @@ image_transform_png_set_rgb_to_gray_add(image_transform *this,
    return (colour_type & PNG_COLOR_MASK_COLOR) != 0;
 }
 
-IT(rgb_to_gray,strip_alpha);
+IT(rgb_to_gray);
+#undef PT
+#define PT ITSTRUCT(rgb_to_gray)
+#endif /* PNG_READ_RGB_TO_GRAY_SUPPORTED */
 
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
 /* png_set_background(png_structp, png_const_color_16p background_color,
  *    int background_gamma_code, int need_expand, double background_gamma)
  * png_set_background_fixed(png_structp, png_const_color_16p background_color,
@@ -4691,19 +5485,54 @@ static void
 image_transform_png_set_background_set(PNG_CONST image_transform *this,
     transform_display *that, png_structp pp, png_infop pi)
 {
+   png_byte colour_type, bit_depth;
+   png_byte random_bytes[8]; /* 8 bytes - 64 bits - the biggest pixel */
    png_color_16 back;
 
-   /* Since we don't know the output bit depth at this point we must use the
-    * input values and ask libpng to expand the chunk as required.
+   /* We need a background colour, because we don't know exactly what transforms
+    * have been set we have to supply the colour in the original file format and
+    * so we need to know what that is!  The background colour is stored in the
+    * transform_display.
+    */
+   RANDOMIZE(random_bytes);
+
+   /* Read the random value, for colour type 3 the background colour is actually
+    * expressed as a 24bit rgb, not an index.
+    */
+   colour_type = that->this.colour_type;
+   if (colour_type == 3)
+   {
+      colour_type = PNG_COLOR_TYPE_RGB;
+      bit_depth = 8;
+   }
+
+   else
+      bit_depth = that->this.bit_depth;
+
+   image_pixel_init(&that->background_colour, random_bytes, colour_type,
+      bit_depth, 0/*x*/, 0/*unused: palette*/);
+
+   /* Extract the background colour from this image_pixel, but make sure the
+    * unused fields of 'back' are garbage.
     */
-   back.index = 255; /* Should not be used */
-   back.gray = back.blue = back.green = back.red =
-      (png_uint_16)((1U << that->this.bit_depth) >> 1);
+   RANDOMIZE(back);
+
+   if (colour_type & PNG_COLOR_MASK_COLOR)
+   {
+      back.red = (png_uint_16)that->background_colour.red;
+      back.green = (png_uint_16)that->background_colour.green;
+      back.blue = (png_uint_16)that->background_colour.blue;
+   }
+
+   else
+      back.gray = (png_uint_16)that->background_colour.red;
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
-      png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1, 0);
+      png_set_background(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1/*need expand*/,
+         0);
 #  else
-      png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE, 1, 0);
+      png_set_background_fixed(pp, &back, PNG_BACKGROUND_GAMMA_FILE,
+         1/*need expand*/, 0);
 #  endif
 
    this->next->set(this->next, that, pp, pi);
@@ -4720,32 +5549,40 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
    /* This is only necessary if the alpha value is less than 1. */
    if (that->alphaf < 1)
    {
-      /* Repeat the calculation above and scale the result: */
-      unsigned int tmp = (1U << display->this.bit_depth);
-      double component = (tmp >> 1)/(double)(tmp-1);
+      PNG_CONST image_pixel *back = &display->background_colour;
 
       /* Now we do the background calculation without any gamma correction. */
       if (that->alphaf <= 0)
       {
-         that->bluef = that->greenf = that->redf = component;
-         that->bluee = that->greene = that->rede = component * DBL_EPSILON;
-         that->blue_sBIT = that->green_sBIT = that->red_sBIT = that->bit_depth;
+         that->redf = back->redf;
+         that->greenf = back->greenf;
+         that->bluef = back->bluef;
+
+         that->rede = back->rede;
+         that->greene = back->greene;
+         that->bluee = back->bluee;
+
+         that->red_sBIT= back->red_sBIT;
+         that->green_sBIT= back->green_sBIT;
+         that->blue_sBIT= back->blue_sBIT;
       }
 
-      else
+      else /* 0 < alpha < 1 */
       {
-         component *= 1-that->alphaf;
-         that->redf = that->redf * that->alphaf + component;
-         that->rede = that->rede * that->alphaf + that->redf * 3 * DBL_EPSILON;
-         that->greenf = that->greenf * that->alphaf + component;
-         that->greene = that->greene * that->alphaf + that->greenf * 3 *
+         double alf = 1 - that->alphaf;
+
+         that->redf = that->redf * that->alphaf + back->redf * alf;
+         that->rede = that->rede * that->alphaf + back->rede * alf +
             DBL_EPSILON;
-         that->bluef = that->bluef * that->alphaf + component;
-         that->bluee = that->bluee * that->alphaf + that->bluef * 3 *
+         that->greenf = that->greenf * that->alphaf + back->greenf * alf;
+         that->greene = that->greene * that->alphaf + back->greene * alf +
+            DBL_EPSILON;
+         that->bluef = that->bluef * that->alphaf + back->bluef * alf;
+         that->bluee = that->bluee * that->alphaf + back->bluee * alf +
             DBL_EPSILON;
       }
 
-      /* Remove the alpha type and set the alpha. */
+      /* Remove the alpha type and set the alpha (not in that order.) */
       that->alphaf = 1;
       that->alphae = 0;
 
@@ -4753,6 +5590,7 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
          that->colour_type = PNG_COLOR_TYPE_RGB;
       else if (that->colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
          that->colour_type = PNG_COLOR_TYPE_GRAY;
+      /* PNG_COLOR_TYPE_PALETTE is not changed */
    }
 
    this->next->mod(this->next, that, pp, display);
@@ -4760,9 +5598,13 @@ image_transform_png_set_background_mod(PNG_CONST image_transform *this,
 
 #define image_transform_png_set_background_add image_transform_default_add
 
-IT(background,rgb_to_gray);
+IT(background);
+#undef PT
+#define PT ITSTRUCT(background)
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
 
-static image_transform *PNG_CONST image_transform_first = &ITSTRUCT(background);
+/* This may just be 'end' if all the transforms are disabled! */
+static image_transform *PNG_CONST image_transform_first = &PT;
 
 static void
 transform_enable(PNG_CONST char *name)
@@ -5014,13 +5856,15 @@ IT(@);
 /* png_set_shift(png_structp, png_const_color_8p true_bits) */
 /*NOTE: TBD NYI */
 
-static int
-test_transform(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
-    int bdlo, int PNG_CONST bdhi, png_uint_32 max)
+static void
+perform_transform_test(png_modifier *pm)
 {
-   for (; bdlo <= bdhi; ++bdlo)
+   png_byte colour_type = 0;
+   png_byte bit_depth = 0;
+   int palette_number = 0;
+
+   while (next_format(&colour_type, &bit_depth, &palette_number))
    {
-      PNG_CONST png_byte bit_depth = DEPTH(bdlo);
       png_uint_32 counter = 0;
       size_t base_pos;
       char name[64];
@@ -5032,48 +5876,28 @@ test_transform(png_modifier* PNG_CONST pm, png_byte PNG_CONST colour_type,
          size_t pos = base_pos;
          PNG_CONST image_transform *list = 0;
 
-         counter = image_transform_add(&list, max, counter, name, sizeof name,
-            &pos, colour_type, bit_depth);
+         /* 'max' is currently hardwired to '1'; this should be settable on the
+          * command line.
+          */
+         counter = image_transform_add(&list, 1/*max*/, counter,
+            name, sizeof name, &pos, colour_type, bit_depth);
 
          if (counter == 0)
             break;
 
          /* The command line can change this to checking interlaced images. */
-         transform_test(pm, FILEID(colour_type, bit_depth, pm->interlace_type,
-            0, 0, 0), list, name);
+         transform_test(pm, FILEID(colour_type, bit_depth, palette_number,
+            pm->interlace_type, 0, 0, 0), list, name);
 
          if (fail(pm))
-            return 0;
+            return;
       }
    }
-
-   return 1; /* keep going */
-}
-
-static void
-perform_transform_test(png_modifier *pm)
-{
-   /* Test each colour type over the valid range of bit depths (expressed as
-    * log2(bit_depth) in turn, stop as soon as any error is detected.
-    */
-   if (!test_transform(pm, 0, 0, READ_BDHI, 1))
-      return;
-
-   if (!test_transform(pm, 2, 3, READ_BDHI, 1))
-      return;
-
-   if (!test_transform(pm, 3, 0, 3, 1))
-      return;
-
-   if (!test_transform(pm, 4, 3, READ_BDHI, 1))
-      return;
-
-   if (!test_transform(pm, 6, 3, READ_BDHI, 1))
-      return;
 }
-
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
 /********************************* GAMMA TESTS ********************************/
+#ifdef PNG_READ_GAMMA_SUPPORTED
 /* Gamma test images. */
 typedef struct gamma_modification
 {
@@ -5226,12 +6050,14 @@ typedef struct gamma_display
    png_modifier*    pm;
    double           file_gamma;
    double           screen_gamma;
+   double           background_gamma;
    png_byte         sbit;
    int              threshold_test;
-   PNG_CONST char*  name;
-   int              speed;
    int              use_input_precision;
-   int              strip16;
+   int              scale16;
+   int              expand16;
+   int              do_background;
+   png_color_16     background_color;
 
    /* Local variables */
    double       maxerrout;
@@ -5239,10 +6065,14 @@ typedef struct gamma_display
    double       maxerrabs;
 } gamma_display;
 
+#define ALPHA_MODE_OFFSET 4
+
 static void
 gamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id,
     double file_gamma, double screen_gamma, png_byte sbit, int threshold_test,
-    int speed, int use_input_precision, int strip16)
+    int use_input_precision, int scale16, int expand16,
+    int do_background, PNG_CONST png_color_16 *pointer_to_the_background_color,
+    double background_gamma)
 {
    /* Standard fields */
    standard_display_init(&dp->this, &pm->this, id, 0/*do_interlace*/);
@@ -5251,11 +6081,17 @@ gamma_display_init(gamma_display *dp, png_modifier *pm, png_uint_32 id,
    dp->pm = pm;
    dp->file_gamma = file_gamma;
    dp->screen_gamma = screen_gamma;
+   dp->background_gamma = background_gamma;
    dp->sbit = sbit;
    dp->threshold_test = threshold_test;
-   dp->speed = speed;
    dp->use_input_precision = use_input_precision;
-   dp->strip16 = strip16;
+   dp->scale16 = scale16;
+   dp->expand16 = expand16;
+   dp->do_background = do_background;
+   if (do_background && pointer_to_the_background_color != 0)
+      dp->background_color = *pointer_to_the_background_color;
+   else
+      memset(&dp->background_color, 0, sizeof dp->background_color);
 
    /* Local variable fields */
    dp->maxerrout = dp->maxerrpc = dp->maxerrabs = 0;
@@ -5272,13 +6108,102 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi)
     * are interactions with sBIT but, internally, libpng makes sbit at most
     * PNG_MAX_GAMMA_8 when doing the following.
     */
-   if (dp->strip16)
-#     ifdef PNG_READ_16_TO_8_SUPPORTED
-         png_set_strip_16(pp);
+   if (dp->scale16)
+#     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
+         png_set_scale_16(pp);
+#     else
+         /* The following works both in 1.5.4 and earlier versions: */
+#        ifdef PNG_READ_16_TO_8_SUPPORTED
+            png_set_strip_16(pp);
+#        else
+            png_error(pp, "scale16 (16 to 8 bit conversion) not supported");
+#        endif
+#     endif
+
+   if (dp->expand16)
+#     ifdef PNG_READ_EXPAND_16_SUPPORTED
+         png_set_expand_16(pp);
 #     else
-         png_error(pp, "strip16 (16 to 8 bit conversion) not supported");
+         png_error(pp, "expand16 (8 to 16 bit conversion) not supported");
 #     endif
 
+   if (dp->do_background >= ALPHA_MODE_OFFSET)
+   {
+#     ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      {
+         /* This tests the alpha mode handling, if supported. */
+         int mode = dp->do_background - ALPHA_MODE_OFFSET;
+
+         /* The gamma value is the output gamma, and is in the standard,
+          * non-inverted, represenation.  It provides a default for the PNG file
+          * gamma, but since the file has a gAMA chunk this does not matter.
+          */
+         PNG_CONST double sg = dp->screen_gamma;
+#        ifndef PNG_FLOATING_POINT_SUPPORTED
+            PNG_CONST png_fixed_point g = (png_fixed_point)(sg*100000+.5);
+#        endif
+
+#        ifdef PNG_FLOATING_POINT_SUPPORTED
+            png_set_alpha_mode(pp, mode, sg);
+#        else
+            png_set_alpha_mode_fixed(pp, mode, g);
+#        endif
+
+         /* However, for the standard Porter-Duff algorithm the output defaults
+          * to be linear, so if the test requires non-linear output it must be
+          * corrected here.
+          */
+         if (mode == PNG_ALPHA_STANDARD && sg != 1)
+         {
+#           ifdef PNG_FLOATING_POINT_SUPPORTED
+               png_set_gamma(pp, sg, dp->file_gamma);
+#           else
+               png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5);
+               png_set_gamma_fixed(pp, g, f);
+#           endif
+         }
+      }
+#     else
+         png_error(pp, "alpha mode handling not supported");
+#     endif
+   }
+
+   else
+   {
+      /* Set up gamma processing. */
+#     ifdef PNG_FLOATING_POINT_SUPPORTED
+         png_set_gamma(pp, dp->screen_gamma, dp->file_gamma);
+#     else
+      {
+         png_fixed_point s = (png_fixed_point)(dp->screen_gamma*100000+.5);
+         png_fixed_point f = (png_fixed_point)(dp->file_gamma*100000+.5);
+         png_set_gamma_fixed(pp, s, f);
+      }
+#     endif
+
+      if (dp->do_background)
+      {
+#     ifdef PNG_READ_BACKGROUND_SUPPORTED
+         /* NOTE: this assumes the caller provided the correct background gamma!
+          */
+         PNG_CONST double bg = dp->background_gamma;
+#        ifndef PNG_FLOATING_POINT_SUPPORTED
+            PNG_CONST png_fixed_point g = (png_fixed_point)(bg*100000+.5);
+#        endif
+
+#        ifdef PNG_FLOATING_POINT_SUPPORTED
+            png_set_background(pp, &dp->background_color, dp->do_background,
+               0/*need_expand*/, bg);
+#        else
+            png_set_background_fixed(pp, &dp->background_color,
+               dp->do_background, 0/*need_expand*/, g);
+#        endif
+#     else
+         png_error(pp, "png_set_background not supported");
+#     endif
+      }
+   }
+
    png_read_update_info(pp, pi);
 
    /* Now we may get a different cbRow: */
@@ -5291,259 +6216,930 @@ gamma_info(png_structp pp, png_infop pi)
    gamma_info_imp(png_get_progressive_ptr(pp), pp, pi);
 }
 
+/* Validate a single component value - the routine gets the input and output
+ * sample values as unscaled PNG component values along with a cache of all the
+ * information required to validate the values.
+ */
+typedef struct validate_info
+{
+   png_structp  pp;
+   gamma_display *dp;
+   png_byte sbit;
+   int use_input_precision;
+   int do_background;
+   int scale16;
+   unsigned int sbit_max;
+   unsigned int isbit_shift;
+   unsigned int outmax;
+
+   double gamma_correction; /* Overall correction required. */
+   double file_inverse;     /* Inverse of file gamma. */
+   double screen_gamma;
+   double screen_inverse;   /* Inverse of screen gamma. */
+
+   double background_red;   /* Linear background value, red or gray. */
+   double background_green;
+   double background_blue;
+
+   double maxabs;
+   double maxpc;
+   double maxcalc;
+   double maxout;
+   double maxout_total;     /* Total including quantization error */
+   double outlog;
+   int    outquant;
+}
+validate_info;
+
 static void
-gamma_image_validate(gamma_display *dp, png_structp pp, png_infop pi,
-    png_const_bytep pRow)
+init_validate_info(validate_info *vi, gamma_display *dp, png_struct *pp,
+    int in_depth, int out_depth)
 {
-   /* Get some constants derived from the input and output file formats: */
-   PNG_CONST png_byte sbit = dp->sbit;
-   PNG_CONST double file_gamma = dp->file_gamma;
-   PNG_CONST double screen_gamma = dp->screen_gamma;
-   PNG_CONST int use_input_precision = dp->use_input_precision;
-   PNG_CONST int speed = dp->speed;
-   PNG_CONST png_byte in_ct = dp->this.colour_type;
-   PNG_CONST png_byte in_bd = dp->this.bit_depth;
-   PNG_CONST png_uint_32 w = dp->this.w;
-   PNG_CONST png_uint_32 h = dp->this.h;
-   PNG_CONST size_t cbRow = dp->this.cbRow;
-   PNG_CONST png_byte out_ct = png_get_color_type(pp, pi);
-   PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi);
-   PNG_CONST unsigned int outmax = (1U<<out_bd)-1;
-   PNG_CONST double maxabs = abserr(dp->pm, out_bd);
-   PNG_CONST double maxout = outerr(dp->pm, out_bd);
-   PNG_CONST double maxpc = pcerr(dp->pm, out_bd);
+   PNG_CONST unsigned int outmax = (1U<<out_depth)-1;
 
-   /* There are three sources of error, firstly the quantization in the
-    * file encoding, determined by sbit and/or the file depth, secondly
-    * the output (screen) gamma and thirdly the output file encoding.
-    *
-    * Since this API receives the screen and file gamma in double
-    * precision it is possible to calculate an exact answer given an input
-    * pixel value.  Therefore we assume that the *input* value is exact -
-    * sample/maxsample - calculate the corresponding gamma corrected
-    * output to the limits of double precision arithmetic and compare with
-    * what libpng returns.
-    *
-    * Since the library must quantize the output to 8 or 16 bits there is
-    * a fundamental limit on the accuracy of the output of +/-.5 - this
-    * quantization limit is included in addition to the other limits
-    * specified by the paramaters to the API.  (Effectively, add .5
-    * everywhere.)
-    *
-    * The behavior of the 'sbit' paramter is defined by section 12.5
-    * (sample depth scaling) of the PNG spec.  That section forces the
-    * decoder to assume that the PNG values have been scaled if sBIT is
-    * present:
-    *
-    *     png-sample = floor( input-sample * (max-out/max-in) + .5);
-    *
-    * This means that only a subset of the possible PNG values should
-    * appear in the input. However, the spec allows the encoder to use a
-    * variety of approximations to the above and doesn't require any
-    * restriction of the values produced.
-    *
-    * Nevertheless the spec requires that the upper 'sBIT' bits of the
-    * value stored in a PNG file be the original sample bits.
-    * Consequently the code below simply scales the top sbit bits by
-    * (1<<sbit)-1 to obtain an original sample value.
-    *
-    * Because there is limited precision in the input it is arguable that
-    * an acceptable result is any valid result from input-.5 to input+.5.
-    * The basic tests below do not do this, however if
-    * 'use_input_precision' is set a subsequent test is performed below.
-    */
-   PNG_CONST int processing = (fabs(screen_gamma*file_gamma-1) >=
-      PNG_GAMMA_THRESHOLD && !dp->threshold_test && !speed && in_ct != 3) ||
-      in_bd != out_bd;
+   vi->pp = pp;
+   vi->dp = dp;
 
-   PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U;
+   if (dp->sbit > 0 && dp->sbit < in_depth)
+   {
+      vi->sbit = dp->sbit;
+      vi->isbit_shift = in_depth - dp->sbit;
+   }
 
-   PNG_CONST double gamma_correction = 1/(file_gamma*screen_gamma);/* Overall */
+   else
+   {
+      vi->sbit = (png_byte)in_depth;
+      vi->isbit_shift = 0;
+   }
 
-   double maxerrout = 0, maxerrabs = 0, maxerrpc = 0;
-   png_uint_32 y;
+   vi->sbit_max = (1U << vi->sbit)-1;
 
-   for (y=0; y<h; ++y, pRow += cbRow)
+   /* This mimics the libpng threshold test, '0' is used to prevent gamma
+    * correction in the validation test.
+    */
+   vi->screen_gamma = dp->screen_gamma;
+   if (fabs(vi->screen_gamma-1) < PNG_GAMMA_THRESHOLD)
+      vi->screen_gamma = vi->screen_inverse = 0;
+   else
+      vi->screen_inverse = 1/vi->screen_gamma;
+
+   vi->use_input_precision = dp->use_input_precision;
+   vi->outmax = outmax;
+   vi->maxabs = abserr(dp->pm, in_depth, out_depth);
+   vi->maxpc = pcerr(dp->pm, in_depth, out_depth);
+   vi->maxcalc = calcerr(dp->pm, in_depth, out_depth);
+   vi->maxout = outerr(dp->pm, in_depth, out_depth);
+   vi->outquant = output_quantization_factor(dp->pm, in_depth, out_depth);
+   vi->maxout_total = vi->maxout + vi->outquant * .5;
+   vi->outlog = outlog(dp->pm, in_depth, out_depth);
+
+   if ((dp->this.colour_type & PNG_COLOR_MASK_ALPHA) != 0 ||
+      (dp->this.colour_type == 3 && dp->this.is_transparent))
    {
-      unsigned int s, x;
-      png_byte std[STANDARD_ROWMAX];
-
-      transform_row(pp, std, in_ct, in_bd, y);
+      vi->do_background = dp->do_background;
 
-      if (processing)
+      if (vi->do_background != 0)
       {
-         for (x=0; x<w; ++x) for (s=0; s<samples_per_pixel; ++s)
-         {
-            /* Input sample values: */
-            PNG_CONST unsigned int
-               id = sample(std, in_ct, in_bd, x, s);
+         PNG_CONST double bg_inverse = 1/dp->background_gamma;
+         double r, g, b;
 
-            PNG_CONST unsigned int
-               od = sample(pRow, out_ct, out_bd, x, s);
+         /* Caller must at least put the gray value into the red channel */
+         r = dp->background_color.red; r /= outmax;
+         g = dp->background_color.green; g /= outmax;
+         b = dp->background_color.blue; b /= outmax;
 
-            PNG_CONST unsigned int
-               isbit = id >> (in_bd-sbit);
+#     if 0
+         /* libpng doesn't do this optimization, if we do pngvalid will fail.
+          */
+         if (fabs(bg_inverse-1) >= PNG_GAMMA_THRESHOLD)
+#     endif
+         {
+            r = pow(r, bg_inverse);
+            g = pow(g, bg_inverse);
+            b = pow(b, bg_inverse);
+         }
 
-            double i, input_sample, encoded_sample, output;
-            double encoded_error, error;
-            double es_lo, es_hi;
+         vi->background_red = r;
+         vi->background_green = g;
+         vi->background_blue = b;
+      }
+   }
+   else
+      vi->do_background = 0;
 
-            /* First check on the 'perfect' result obtained from the
-             * digitized input value, id, and compare this against the
-             * actual digitized result, 'od'.  'i' is the input result
-             * in the range 0..1:
-             *
-             * NOTE: sBIT should be taken into account here but isn't,
-             * as described above.
+   if (vi->do_background == 0)
+      vi->background_red = vi->background_green = vi->background_blue = 0;
+
+   vi->gamma_correction = 1/(dp->file_gamma*dp->screen_gamma);
+   if (fabs(vi->gamma_correction-1) < PNG_GAMMA_THRESHOLD)
+      vi->gamma_correction = 0;
+
+   vi->file_inverse = 1/dp->file_gamma;
+   if (fabs(vi->file_inverse-1) < PNG_GAMMA_THRESHOLD)
+      vi->file_inverse = 0;
+
+   vi->scale16 = dp->scale16;
+}
+
+/* This function handles composition of a single non-alpha component.  The
+ * argument is the input sample value, in the range 0..1, and the alpha value.
+ * The result is the composed, linear, input sample.  If alpha is less than zero
+ * this is the alpha component and the function should not be called!
+ */
+static double
+gamma_component_compose(int do_background, double input_sample, double alpha,
+   double background, int *compose)
+{
+   switch (do_background)
+   {
+      case PNG_BACKGROUND_GAMMA_SCREEN:
+      case PNG_BACKGROUND_GAMMA_FILE:
+      case PNG_BACKGROUND_GAMMA_UNIQUE:
+         /* Standard PNG background processing. */
+         if (alpha < 1)
+         {
+            if (alpha > 0)
+            {
+               input_sample = input_sample * alpha + background * (1-alpha);
+               if (compose != NULL)
+                  *compose = 1;
+            }
+
+            else
+               input_sample = background;
+         }
+         break;
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD:
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN:
+         /* The components are premultiplied in either case and the output is
+          * gamma encoded (to get standard Porter-Duff we expect the output
+          * gamma to be set to 1.0!)
+          */
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED:
+         /* The optimization is that the partial-alpha entries are linear
+          * while the opaque pixels are gamma encoded, but this only affects the
+          * output encoding.
+          */
+         if (alpha < 1)
+         {
+            if (alpha > 0)
+            {
+               input_sample *= alpha;
+               if (compose != NULL)
+                  *compose = 1;
+            }
+
+            else
+               input_sample = 0;
+         }
+         break;
+#endif
+
+      default:
+         /* Standard cases where no compositing is done (so the component
+          * value is already correct.)
+          */
+         break;
+   }
+
+   return input_sample;
+}
+
+/* This API returns the encoded *input* component, in the range 0..1 */
+static double
+gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi,
+    PNG_CONST unsigned int id, PNG_CONST unsigned int od,
+    PNG_CONST double alpha /* <0 for the alpha channel itself */,
+    PNG_CONST double background /* component background value */)
+{
+   PNG_CONST unsigned int isbit = id >> vi->isbit_shift;
+   PNG_CONST unsigned int sbit_max = vi->sbit_max;
+   PNG_CONST unsigned int outmax = vi->outmax;
+   PNG_CONST int do_background = vi->do_background;
+
+   double i;
+
+   /* First check on the 'perfect' result obtained from the digitized input
+    * value, id, and compare this against the actual digitized result, 'od'.
+    * 'i' is the input result in the range 0..1:
+    */
+   i = isbit; i /= sbit_max;
+
+   /* Check for the fast route: if we don't do any background composition or if
+    * this is the alpha channel ('alpha' < 0) or if the pixel is opaque then
+    * just use the gamma_correction field to correct to the final output gamma.
+    */
+   if (alpha == 1 /* opaque pixel component */ || !do_background
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      || do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_PNG
+#endif
+      || (alpha < 0 /* alpha channel */
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      && do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN
+#endif
+      ))
+   {
+      /* Then get the gamma corrected version of 'i' and compare to 'od', any
+       * error less than .5 is insignificant - just quantization of the output
+       * value to the nearest digital value (nevertheless the error is still
+       * recorded - it's interesting ;-)
+       */
+      double encoded_sample = i;
+      double encoded_error;
+
+      /* alpha less than 0 indicates the alpha channel, which is always linear
+       */
+      if (alpha >= 0 && vi->gamma_correction > 0)
+         encoded_sample = pow(encoded_sample, vi->gamma_correction);
+      encoded_sample *= outmax;
+
+      encoded_error = fabs(od-encoded_sample);
+
+      if (encoded_error > vi->dp->maxerrout)
+         vi->dp->maxerrout = encoded_error;
+
+      if (encoded_error < vi->maxout_total && encoded_error < vi->outlog)
+         return i;
+   }
+
+   /* The slow route - attempt to do linear calculations. */
+   /* There may be an error, or background processing is required, so calculate
+    * the actual sample values - unencoded light intensity values.  Note that in
+    * practice these are not completely unencoded because they include a
+    * 'viewing correction' to decrease or (normally) increase the perceptual
+    * contrast of the image.  There's nothing we can do about this - we don't
+    * know what it is - so assume the unencoded value is perceptually linear.
+    */
+   {
+      double input_sample = i; /* In range 0..1 */
+      double output, error, encoded_sample, encoded_error;
+      double es_lo, es_hi;
+      int compose = 0;           /* Set to one if composition done */
+      int output_is_encoded;     /* Set if encoded to screen gamma */
+      int log_max_error = 1;     /* Check maximum error values */
+      png_const_charp pass = 0;  /* Reason test passes (or 0 for fail) */
+
+      /* Convert to linear light (with the above caveat.)  The alpha channel is
+       * already linear.
+       */
+      if (alpha >= 0)
+      {
+         int tcompose;
+
+         if (vi->file_inverse > 0)
+            input_sample = pow(input_sample, vi->file_inverse);
+
+         /* Handle the compose processing: */
+         tcompose = 0;
+         input_sample = gamma_component_compose(do_background, input_sample,
+            alpha, background, &tcompose);
+
+         if (tcompose)
+            compose = 1;
+      }
+
+      /* And similarly for the output value, but we need to check the background
+       * handling to linearize it correctly.
+       */
+      output = od;
+      output /= outmax;
+
+      output_is_encoded = vi->screen_gamma > 0;
+
+      if (alpha < 0) /* The alpha channel */
+      {
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+         if (do_background != ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN)
+#endif
+         {
+            /* In all other cases the output alpha channel is linear already,
+             * don't log errors here, they are much larger in linear data.
              */
-            i = isbit; i /= (1U<<sbit)-1;
+            output_is_encoded = 0;
+            log_max_error = 0;
+         }
+      }
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      else /* A component */
+      {
+         if (do_background == ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED &&
+            alpha < 1) /* the optimized case - linear output */
+         {
+            if (alpha > 0) log_max_error = 0;
+            output_is_encoded = 0;
+         }
+      }
+#endif
+
+      if (output_is_encoded)
+         output = pow(output, vi->screen_gamma);
+
+      /* Calculate (or recalculate) the encoded_sample value and repeat the
+       * check above (unnecessary if we took the fast route, but harmless.)
+       */
+      encoded_sample = input_sample;
+      if (output_is_encoded)
+         encoded_sample = pow(encoded_sample, vi->screen_inverse);
+      encoded_sample *= outmax;
+
+      encoded_error = fabs(od-encoded_sample);
+
+      /* Don't log errors in the alpha channel, or the 'optimized' case,
+       * neither are significant to the overall perception.
+       */
+      if (log_max_error && encoded_error > vi->dp->maxerrout)
+         vi->dp->maxerrout = encoded_error;
+
+      if (encoded_error < vi->maxout_total)
+      {
+         if (encoded_error < vi->outlog)
+            return i;
+
+         /* Test passed but error is bigger than the log limit, record why the
+          * test passed:
+          */
+         pass = "less than maxout:\n";
+      }
+
+      /* i: the original input value in the range 0..1
+       *
+       * pngvalid calculations:
+       *  input_sample: linear result; i linearized and composed, range 0..1
+       *  encoded_sample: encoded result; input_sample scaled to ouput bit depth
+       *
+       * libpng calculations:
+       *  output: linear result; od scaled to 0..1 and linearized
+       *  od: encoded result from libpng
+       */
+
+      /* Now we have the numbers for real errors, both absolute values as as a
+       * percentage of the correct value (output):
+       */
+      error = fabs(input_sample-output);
+
+      if (log_max_error && error > vi->dp->maxerrabs)
+         vi->dp->maxerrabs = error;
+
+      /* The following is an attempt to ignore the tendency of quantization to
+       * dominate the percentage errors for lower result values:
+       */
+      if (log_max_error && input_sample > .5)
+      {
+         double percentage_error = error/input_sample;
+         if (percentage_error > vi->dp->maxerrpc)
+            vi->dp->maxerrpc = percentage_error;
+      }
+
+      /* Now calculate the digitization limits for 'encoded_sample' using the
+       * 'max' values.  Note that maxout is in the encoded space but maxpc and
+       * maxabs are in linear light space.
+       *
+       * First find the maximum error in linear light space, range 0..1:
+       */
+      {
+         double tmp = input_sample * vi->maxpc;
+         if (tmp < vi->maxabs) tmp = vi->maxabs;
+         /* If 'compose' is true the composition was done in linear space using
+          * integer arithmetic.  This introduces an extra error of +/- 0.5 (at
+          * least) in the integer space used.  'maxcalc' records this, taking
+          * into account the possibility that even for 16 bit output 8 bit space
+          * may have been used.
+          */
+         if (compose && tmp < vi->maxcalc) tmp = vi->maxcalc;
+
+         /* The 'maxout' value refers to the encoded result, to compare with
+          * this encode input_sample adjusted by the maximum error (tmp) above.
+          */
+         es_lo = encoded_sample - vi->maxout;
+
+         if (es_lo > 0 && input_sample-tmp > 0)
+         {
+            double low_value = input_sample-tmp;
+            if (output_is_encoded)
+               low_value = pow(low_value, vi->screen_inverse);
+            low_value *= outmax;
+            if (low_value < es_lo) es_lo = low_value;
+
+            /* Quantize this appropriately: */
+            es_lo = ceil(es_lo / vi->outquant - .5) * vi->outquant;
+         }
+
+         else
+            es_lo = 0;
+
+         es_hi = encoded_sample + vi->maxout;
+
+         if (es_hi < outmax && input_sample+tmp < 1)
+         {
+            double high_value = input_sample+tmp;
+            if (output_is_encoded)
+               high_value = pow(high_value, vi->screen_inverse);
+            high_value *= outmax;
+            if (high_value > es_hi) es_hi = high_value;
 
-            /* Then get the gamma corrected version of 'i' and compare
-             * to 'od', any error less than .5 is insignificant - just
-             * quantization of the output value to the nearest digital
-             * value (nevertheless the error is still recorded - it's
-             * interesting ;-)
+            es_hi = floor(es_hi / vi->outquant + .5) * vi->outquant;
+         }
+
+         else
+            es_hi = outmax;
+      }
+
+      /* The primary test is that the final encoded value returned by the
+       * library should be between the two limits (inclusive) that were
+       * calculated above.
+       */
+      if (od >= es_lo && od <= es_hi)
+      {
+         /* The value passes, but we may need to log the information anyway. */
+         if (encoded_error < vi->outlog)
+            return i;
+
+         if (pass == 0)
+            pass = "within digitization limits:\n";
+      }
+
+      {
+         /* There has been an error in processing, or we need to log this
+          * value.
+          */
+         double is_lo, is_hi;
+
+         /* pass is set at this point if either of the tests above would have
+          * passed.  Don't do these additional tests here - just log the
+          * original [es_lo..es_hi] values.
+          */
+         if (pass == 0 && vi->use_input_precision)
+         {
+            /* Ok, something is wrong - this actually happens in current libpng
+             * 16-to-8 processing.  Assume that the input value (id, adjusted
+             * for sbit) can be anywhere between value-.5 and value+.5 - quite a
+             * large range if sbit is low.
              */
-            encoded_sample = pow(i, gamma_correction) * outmax;
-            encoded_error = fabs(od-encoded_sample);
-
-            if (encoded_error > maxerrout)
-               maxerrout = encoded_error;
-
-            if (encoded_error < .5+maxout)
-               continue;
-
-            /* There may be an error, so calculate the actual sample
-             * values - unencoded light intensity values.  Note that
-             * in practice these are not unencoded because they
-             * include a 'viewing correction' to decrease or
-             * (normally) increase the perceptual contrast of the
-             * image.  There's nothing we can do about this - we don't
-             * know what it is - so assume the unencoded value is
-             * perceptually linear.
+            double tmp = (isbit - .5)/sbit_max;
+
+            if (tmp <= 0)
+               tmp = 0;
+
+            else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1)
+               tmp = pow(tmp, vi->file_inverse);
+
+            tmp = gamma_component_compose(do_background, tmp, alpha, background,
+               NULL);
+
+            if (output_is_encoded && tmp > 0 && tmp < 1)
+               tmp = pow(tmp, vi->screen_inverse);
+
+            is_lo = ceil(outmax * tmp - vi->maxout_total);
+
+            if (is_lo < 0)
+               is_lo = 0;
+
+            tmp = (isbit + .5)/sbit_max;
+
+            if (tmp <= 0)
+               tmp = 0;
+
+            else if (alpha >= 0 && vi->file_inverse > 0 && tmp < 1)
+               tmp = pow(tmp, vi->file_inverse);
+
+            tmp = gamma_component_compose(do_background, tmp, alpha, background,
+               NULL);
+
+            if (output_is_encoded && tmp > 0 && tmp < 1)
+               tmp = pow(tmp, vi->screen_inverse);
+
+            is_hi = floor(outmax * tmp + vi->maxout_total);
+
+            if (is_hi > outmax)
+               is_hi = outmax;
+
+            if (!(od < is_lo || od > is_hi))
+            {
+               if (encoded_error < vi->outlog)
+                  return i;
+
+               pass = "within input precision limits:\n";
+            }
+
+            /* One last chance.  If this is an alpha channel and the 16to8
+             * option has been used and 'inaccurate' scaling is used then the
+             * bit reduction is obtained by simply using the top 8 bits of the
+             * value.
+             *
+             * This is only done for older libpng versions when the 'inaccurate'
+             * (chop) method of scaling was used.
              */
-            input_sample = pow(i, 1/file_gamma); /* In range 0..1 */
-            output = od;
-            output /= outmax;
-            output = pow(output, screen_gamma);
+#           ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+#              if PNG_LIBPNG_VER < 10504
+                  /* This may be required for other components in the future,
+                   * but at present the presence of gamma correction effectively
+                   * prevents the errors in the component scaling (I don't quite
+                   * understand why, but since it's better this way I care not
+                   * to ask, JB 20110419.)
+                   */
+                  if (pass == 0 && alpha < 0 && vi->scale16 && vi->sbit > 8 &&
+                     vi->sbit + vi->isbit_shift == 16)
+                  {
+                     tmp = ((id >> 8) - .5)/255;
+
+                     if (tmp > 0)
+                     {
+                        is_lo = ceil(outmax * tmp - vi->maxout_total);
+                        if (is_lo < 0) is_lo = 0;
+                     }
+
+                     else
+                        is_lo = 0;
+
+                     tmp = ((id >> 8) + .5)/255;
+
+                     if (tmp < 1)
+                     {
+                        is_hi = floor(outmax * tmp + vi->maxout_total);
+                        if (is_hi > outmax) is_hi = outmax;
+                     }
 
-            /* Now we have the numbers for real errors, both absolute
-             * values as as a percentage of the correct value (output):
+                     else
+                        is_hi = outmax;
+
+                     if (!(od < is_lo || od > is_hi))
+                     {
+                        if (encoded_error < vi->outlog)
+                           return i;
+
+                        pass = "within 8 bit limits:\n";
+                     }
+                  }
+#              endif
+#           endif
+         }
+         else /* !use_input_precision */
+            is_lo = es_lo, is_hi = es_hi;
+
+         /* Attempt to output a meaningful error/warning message: the message
+          * output depends on the background/composite operation being performed
+          * because this changes what parameters were actually used above.
+          */
+         {
+            size_t pos = 0;
+            /* Need either 1/255 or 1/65535 precision here; 3 or 6 decimal
+             * places.  Just use outmax to work out which.
              */
-            error = fabs(input_sample-output);
+            int precision = (outmax >= 1000 ? 6 : 3);
+            int use_input=1, use_background=0, do_compose=0;
+            char msg[256];
 
-            if (error > maxerrabs)
-               maxerrabs = error;
+            if (pass != 0)
+               pos = safecat(msg, sizeof msg, pos, "\n\t");
 
-            /* The following is an attempt to ignore the tendency of
-             * quantization to dominate the percentage errors for low
-             * output sample values:
+            /* Set up the various flags, the output_is_encoded flag above
+             * is also used below.  do_compose is just a double check.
              */
-            if (input_sample*maxpc > .5+maxabs)
+            switch (do_background)
             {
-               double percentage_error = error/input_sample;
-               if (percentage_error > maxerrpc) maxerrpc = percentage_error;
+            case PNG_BACKGROUND_GAMMA_SCREEN:
+            case PNG_BACKGROUND_GAMMA_FILE:
+            case PNG_BACKGROUND_GAMMA_UNIQUE:
+               use_background = (alpha >= 0 && alpha < 1);
+               /*FALL THROUGH*/
+#           ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+               case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD:
+               case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN:
+               case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED:
+#           endif /* ALPHA_MODE_SUPPORTED */
+               do_compose = (alpha >= 0 && alpha < 1);
+               use_input = (alpha != 0);
+               break;
+
+            default:
+               break;
             }
 
-            /* Now calculate the digitization limits for
-             * 'encoded_sample' using the 'max' values.  Note that
-             * maxout is in the encoded space but maxpc and maxabs are
-             * in linear light space.
-             *
-             * First find the maximum error in linear light space,
-             * range 0..1:
+            /* Check the 'compose' flag */
+            if (compose != do_compose)
+               png_error(vi->pp, "internal error (compose)");
+
+            /* 'name' is the component name */
+            pos = safecat(msg, sizeof msg, pos, name);
+            pos = safecat(msg, sizeof msg, pos, "(");
+            pos = safecatn(msg, sizeof msg, pos, id);
+            if (use_input || pass != 0/*logging*/)
+            {
+               if (isbit != id)
+               {
+                  /* sBIT has reduced the precision of the input: */
+                  pos = safecat(msg, sizeof msg, pos, ", sbit(");
+                  pos = safecatn(msg, sizeof msg, pos, vi->sbit);
+                  pos = safecat(msg, sizeof msg, pos, "): ");
+                  pos = safecatn(msg, sizeof msg, pos, isbit);
+               }
+               pos = safecat(msg, sizeof msg, pos, "/");
+               /* The output is either "id/max" or "id sbit(sbit): isbit/max" */
+               pos = safecatn(msg, sizeof msg, pos, vi->sbit_max);
+            }
+            pos = safecat(msg, sizeof msg, pos, ")");
+
+            /* A component may have been multiplied (in linear space) by the
+             * alpha value, 'compose' says whether this is relevant.
              */
+            if (compose || pass != 0)
             {
-               double tmp = input_sample * maxpc;
-               if (tmp < maxabs) tmp = maxabs;
+               /* If any form of composition is being done report our
+                * calculated linear value here (the code above doesn't record
+                * the input value before composition is performed, so what
+                * gets reported is the value after composition.)
+                */
+               if (use_input || pass != 0)
+               {
+                  if (vi->file_inverse > 0)
+                  {
+                     pos = safecat(msg, sizeof msg, pos, "^");
+                     pos = safecatd(msg, sizeof msg, pos, vi->file_inverse, 2);
+                  }
+
+                  else
+                     pos = safecat(msg, sizeof msg, pos, "[linear]");
 
-               /* Low bound - the minimum of the three: */
-               es_lo = encoded_sample - maxout;
+                  pos = safecat(msg, sizeof msg, pos, "*(alpha)");
+                  pos = safecatd(msg, sizeof msg, pos, alpha, precision);
+               }
 
-               if (es_lo > 0 && input_sample-tmp > 0)
+               /* Now record the *linear* background value if it was used
+                * (this function is not passed the original, non-linear,
+                * value but it is contained in the test name.)
+                */
+               if (use_background)
                {
-                  double low_value = outmax * pow(input_sample-tmp,
-                     1/screen_gamma);
-                  if (low_value < es_lo) es_lo = low_value;
+                  pos = safecat(msg, sizeof msg, pos, use_input ? "+" : " ");
+                  pos = safecat(msg, sizeof msg, pos, "(background)");
+                  pos = safecatd(msg, sizeof msg, pos, background, precision);
+                  pos = safecat(msg, sizeof msg, pos, "*");
+                  pos = safecatd(msg, sizeof msg, pos, 1-alpha, precision);
+               }
+            }
+
+            /* Report the calculated value (input_sample) and the linearized
+             * libpng value (output) unless this is just a component gamma
+             * correction.
+             */
+            if (compose || alpha < 0 || pass != 0)
+            {
+               pos = safecat(msg, sizeof msg, pos,
+                  pass != 0 ? " =\n\t" : " = ");
+               pos = safecatd(msg, sizeof msg, pos, input_sample, precision);
+               pos = safecat(msg, sizeof msg, pos, " (libpng: ");
+               pos = safecatd(msg, sizeof msg, pos, output, precision);
+               pos = safecat(msg, sizeof msg, pos, ")");
+
+               /* Finally report the output gamma encoding, if any. */
+               if (output_is_encoded)
+               {
+                  pos = safecat(msg, sizeof msg, pos, " ^");
+                  pos = safecatd(msg, sizeof msg, pos, vi->screen_inverse, 2);
+                  pos = safecat(msg, sizeof msg, pos, "(to screen) =");
                }
 
                else
-                  es_lo = 0;
+                  pos = safecat(msg, sizeof msg, pos, " [screen is linear] =");
+            }
 
-               es_hi = encoded_sample + maxout;
+            if ((!compose && alpha >= 0) || pass != 0)
+            {
+               if (pass != 0) /* logging */
+                  pos = safecat(msg, sizeof msg, pos, "\n\t[overall:");
 
-               if (es_hi < outmax && input_sample+tmp < 1)
+               /* This is the non-composition case, the internal linear
+                * values are irrelevant (though the log below will reveal
+                * them.)  Output a much shorter warning/error message and report
+                * the overall gamma correction.
+                */
+               if (vi->gamma_correction > 0)
                {
-                  double high_value = outmax * pow(input_sample+tmp,
-                     1/screen_gamma);
-                  if (high_value > es_hi) es_hi = high_value;
+                  pos = safecat(msg, sizeof msg, pos, " ^");
+                  pos = safecatd(msg, sizeof msg, pos, vi->gamma_correction, 2);
+                  pos = safecat(msg, sizeof msg, pos, "(gamma correction) =");
                }
 
                else
-                  es_hi = outmax;
+                  pos = safecat(msg, sizeof msg, pos,
+                     " [no gamma correction] =");
+
+               if (pass != 0)
+                  pos = safecat(msg, sizeof msg, pos, "]");
             }
 
-            /* The primary test is that the final encoded value
-             * returned by the library should be between the two limits
-             * (inclusive) that were calculated above.  At this point
-             * quantization of the output must be taken into account.
+            /* This is our calculated encoded_sample which should (but does
+             * not) match od:
              */
-            if (od+.5 < es_lo || od-.5 > es_hi)
+            pos = safecat(msg, sizeof msg, pos, pass != 0 ? "\n\t" : " ");
+            pos = safecatd(msg, sizeof msg, pos, is_lo, 1);
+            pos = safecat(msg, sizeof msg, pos, " < ");
+            pos = safecatd(msg, sizeof msg, pos, encoded_sample, 1);
+            pos = safecat(msg, sizeof msg, pos, " (libpng: ");
+            pos = safecatn(msg, sizeof msg, pos, od);
+            pos = safecat(msg, sizeof msg, pos, ")");
+            pos = safecat(msg, sizeof msg, pos, "/");
+            pos = safecatn(msg, sizeof msg, pos, outmax);
+            pos = safecat(msg, sizeof msg, pos, " < ");
+            pos = safecatd(msg, sizeof msg, pos, is_hi, 1);
+
+            if (pass == 0) /* The error condition */
             {
-               /* There has been an error in processing. */
-               double is_lo, is_hi;
+#              ifdef PNG_WARNINGS_SUPPORTED
+                  png_warning(vi->pp, msg);
+#              else
+                  store_warning(vi->pp, msg);
+#              endif
+            }
 
-               if (use_input_precision)
-               {
-                  /* Ok, something is wrong - this actually happens in
-                   * current libpng sbit processing.  Assume that the
-                   * input value (id, adjusted for sbit) can be
-                   * anywhere between value-.5 and value+.5 - quite a
-                   * large range if sbit is low.
-                   */
-                  double tmp = (isbit - .5)/((1U<<sbit)-1);
+            else /* logging this value */
+               store_verbose(&vi->dp->pm->this, vi->pp, pass, msg);
+         }
+      }
+   }
 
-                  if (tmp > 0)
-                  {
-                     is_lo = outmax * pow(tmp, gamma_correction) - maxout;
-                     if (is_lo < 0) is_lo = 0;
-                  }
+   return i;
+}
 
-                  else
-                     is_lo = 0;
+static void
+gamma_image_validate(gamma_display *dp, png_structp pp, png_infop pi)
+{
+   /* Get some constants derived from the input and output file formats: */
+   PNG_CONST png_store* PNG_CONST ps = dp->this.ps;
+   PNG_CONST png_byte in_ct = dp->this.colour_type;
+   PNG_CONST png_byte in_bd = dp->this.bit_depth;
+   PNG_CONST png_uint_32 w = dp->this.w;
+   PNG_CONST png_uint_32 h = dp->this.h;
+   PNG_CONST size_t cbRow = dp->this.cbRow;
+   PNG_CONST png_byte out_ct = png_get_color_type(pp, pi);
+   PNG_CONST png_byte out_bd = png_get_bit_depth(pp, pi);
+
+   /* There are three sources of error, firstly the quantization in the
+    * file encoding, determined by sbit and/or the file depth, secondly
+    * the output (screen) gamma and thirdly the output file encoding.
+    *
+    * Since this API receives the screen and file gamma in double
+    * precision it is possible to calculate an exact answer given an input
+    * pixel value.  Therefore we assume that the *input* value is exact -
+    * sample/maxsample - calculate the corresponding gamma corrected
+    * output to the limits of double precision arithmetic and compare with
+    * what libpng returns.
+    *
+    * Since the library must quantize the output to 8 or 16 bits there is
+    * a fundamental limit on the accuracy of the output of +/-.5 - this
+    * quantization limit is included in addition to the other limits
+    * specified by the paramaters to the API.  (Effectively, add .5
+    * everywhere.)
+    *
+    * The behavior of the 'sbit' paramter is defined by section 12.5
+    * (sample depth scaling) of the PNG spec.  That section forces the
+    * decoder to assume that the PNG values have been scaled if sBIT is
+    * present:
+    *
+    *     png-sample = floor( input-sample * (max-out/max-in) + .5);
+    *
+    * This means that only a subset of the possible PNG values should
+    * appear in the input. However, the spec allows the encoder to use a
+    * variety of approximations to the above and doesn't require any
+    * restriction of the values produced.
+    *
+    * Nevertheless the spec requires that the upper 'sBIT' bits of the
+    * value stored in a PNG file be the original sample bits.
+    * Consequently the code below simply scales the top sbit bits by
+    * (1<<sbit)-1 to obtain an original sample value.
+    *
+    * Because there is limited precision in the input it is arguable that
+    * an acceptable result is any valid result from input-.5 to input+.5.
+    * The basic tests below do not do this, however if 'use_input_precision'
+    * is set a subsequent test is performed below.
+    */
+   PNG_CONST unsigned int samples_per_pixel = (out_ct & 2U) ? 3U : 1U;
+   int processing;
+   png_uint_32 y;
+   PNG_CONST store_palette_entry *in_palette = dp->this.palette;
+   PNG_CONST int in_is_transparent = dp->this.is_transparent;
+   int out_npalette = -1;
+   int out_is_transparent = 0; /* Just refers to the palette case */
+   store_palette out_palette;
+   validate_info vi;
+
+   /* Check for row overwrite errors */
+   store_image_check(dp->this.ps, pp, 0);
+
+   /* Supply the input and output sample depths here - 8 for an indexed image,
+    * otherwise the bit depth.
+    */
+   init_validate_info(&vi, dp, pp, in_ct==3?8:in_bd, out_ct==3?8:out_bd);
 
-                  tmp = (isbit + .5)/((1U<<sbit)-1);
+   processing = (vi.gamma_correction > 0 && !dp->threshold_test)
+      || in_bd != out_bd || in_ct != out_ct || vi.do_background;
 
-                  if (tmp < 1)
-                  {
-                     is_hi = outmax * pow(tmp, gamma_correction) + maxout;
-                     if (is_hi > outmax) is_hi = outmax;
-                  }
+   /* TODO: FIX THIS: MAJOR BUG!  If the transformations all happen inside
+    * the palette there is no way of finding out, because libpng fails to
+    * update the palette on png_read_update_info.  Indeed, libpng doesn't
+    * even do the required work until much later, when it doesn't have any
+    * info pointer.  Oops.  For the moment 'processing' is turned off if
+    * out_ct is palette.
+    */
+   if (in_ct == 3 && out_ct == 3)
+      processing = 0;
 
-                  else
-                     is_hi = outmax;
+   if (processing && out_ct == 3)
+      out_is_transparent = read_palette(out_palette, &out_npalette, pp, pi);
 
-                  if (!(od+.5 < is_lo || od-.5 > is_hi))
-                     continue;
-               }
-               else
-                  is_lo = es_lo, is_hi = es_hi;
+   for (y=0; y<h; ++y)
+   {
+      png_const_bytep pRow = store_image_row(ps, pp, 0, y);
+      png_byte std[STANDARD_ROWMAX];
+
+      transform_row(pp, std, in_ct, in_bd, y);
+
+      if (processing)
+      {
+         unsigned int x;
+
+         for (x=0; x<w; ++x)
+         {
+            double alpha = 1; /* serves as a flag value */
+
+            /* Record the palette index for index images. */
+            PNG_CONST unsigned int in_index =
+               in_ct == 3 ? sample(std, 3, in_bd, x, 0) : 256;
+            PNG_CONST unsigned int out_index =
+               out_ct == 3 ? sample(std, 3, out_bd, x, 0) : 256;
 
+            /* Handle input alpha - png_set_background will cause the output
+             * alpha to disappear so there is nothing to check.
+             */
+            if ((in_ct & PNG_COLOR_MASK_ALPHA) != 0 || (in_ct == 3 &&
+               in_is_transparent))
+            {
+               PNG_CONST unsigned int input_alpha = in_ct == 3 ?
+                  dp->this.palette[in_index].alpha :
+                  sample(std, in_ct, in_bd, x, samples_per_pixel);
+
+               unsigned int output_alpha = 65536 /* as a flag value */;
+
+               if (out_ct == 3)
                {
-                  char msg[256];
+                  if (out_is_transparent)
+                     output_alpha = out_palette[out_index].alpha;
+               }
+
+               else if ((out_ct & PNG_COLOR_MASK_ALPHA) != 0)
+                  output_alpha = sample(pRow, out_ct, out_bd, x,
+                     samples_per_pixel);
 
-                  sprintf(msg,
-                   "error: %.3f; %u{%u;%u} -> %u not %.2f (%.1f-%.1f)",
-                     od-encoded_sample, id, sbit, isbit, od,
-                     encoded_sample, is_lo, is_hi);
+               if (output_alpha != 65536)
+                  alpha = gamma_component_validate("alpha", &vi, input_alpha,
+                     output_alpha, -1/*alpha*/, 0/*background*/);
 
-                  png_warning(pp, msg);
+               else /* no alpha in output */
+               {
+                  /* This is a copy of the calculation of 'i' above in order to
+                   * have the alpha value to use in the background calculation.
+                   */
+                  alpha = input_alpha >> vi.isbit_shift;
+                  alpha /= vi.sbit_max;
                }
             }
+
+            /* Handle greyscale or RGB components. */
+            if ((in_ct & PNG_COLOR_MASK_COLOR) == 0) /* greyscale */
+               (void)gamma_component_validate("gray", &vi,
+                  sample(std, in_ct, in_bd, x, 0),
+                  sample(pRow, out_ct, out_bd, x, 0), alpha/*component*/,
+                  vi.background_red);
+            else /* RGB or palette */
+            {
+               (void)gamma_component_validate("red", &vi,
+                  in_ct == 3 ? in_palette[in_index].red :
+                     sample(std, in_ct, in_bd, x, 0),
+                  out_ct == 3 ? out_palette[out_index].red :
+                     sample(pRow, out_ct, out_bd, x, 0),
+                  alpha/*component*/, vi.background_red);
+
+               (void)gamma_component_validate("green", &vi,
+                  in_ct == 3 ? in_palette[in_index].green :
+                     sample(std, in_ct, in_bd, x, 1),
+                  out_ct == 3 ? out_palette[out_index].green :
+                     sample(pRow, out_ct, out_bd, x, 1),
+                  alpha/*component*/, vi.background_green);
+
+               (void)gamma_component_validate("blue", &vi,
+                  in_ct == 3 ? in_palette[in_index].blue :
+                     sample(std, in_ct, in_bd, x, 2),
+                  out_ct == 3 ? out_palette[out_index].blue :
+                     sample(pRow, out_ct, out_bd, x, 2),
+                  alpha/*component*/, vi.background_blue);
+            }
          }
       }
 
-      else if (!speed && memcmp(std, pRow, cbRow) != 0)
+      else if (memcmp(std, pRow, cbRow) != 0)
       {
          char msg[64];
 
@@ -5554,9 +7150,6 @@ gamma_image_validate(gamma_display *dp, png_structp pp, png_infop pi,
       }
    } /* row (y) loop */
 
-   dp->maxerrout = maxerrout;
-   dp->maxerrabs = maxerrabs;
-   dp->maxerrpc = maxerrpc;
    dp->this.ps->validated = 1;
 }
 
@@ -5565,7 +7158,8 @@ gamma_end(png_structp pp, png_infop pi)
 {
    gamma_display *dp = png_get_progressive_ptr(pp);
 
-   gamma_image_validate(dp, pp, pi, dp->this.ps->image);
+   if (!dp->this.speed)
+      gamma_image_validate(dp, pp, pi);
 }
 
 /* A single test run checking a gamma transformation.
@@ -5576,18 +7170,23 @@ gamma_end(png_structp pp, png_infop pi)
  */
 static void
 gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
-    PNG_CONST png_byte bit_depthIn, PNG_CONST int interlace_typeIn,
+    PNG_CONST png_byte bit_depthIn, PNG_CONST int palette_numberIn,
+    PNG_CONST int interlace_typeIn,
     PNG_CONST double file_gammaIn, PNG_CONST double screen_gammaIn,
     PNG_CONST png_byte sbitIn, PNG_CONST int threshold_testIn,
-    PNG_CONST char *name, PNG_CONST int speedIn,
-    PNG_CONST int use_input_precisionIn, PNG_CONST int strip16In)
+    PNG_CONST char *name,
+    PNG_CONST int use_input_precisionIn, PNG_CONST int scale16In,
+    PNG_CONST int expand16In, PNG_CONST int do_backgroundIn,
+    PNG_CONST png_color_16 *bkgd_colorIn, double bkgd_gammaIn)
 {
    gamma_display d;
    context(&pmIn->this, fault);
 
    gamma_display_init(&d, pmIn, FILEID(colour_typeIn, bit_depthIn,
-      interlace_typeIn, 0, 0, 0), file_gammaIn, screen_gammaIn, sbitIn,
-      threshold_testIn, speedIn, use_input_precisionIn, strip16In);
+      palette_numberIn, interlace_typeIn, 0, 0, 0),
+      file_gammaIn, screen_gammaIn, sbitIn,
+      threshold_testIn, use_input_precisionIn, scale16In,
+      expand16In, do_backgroundIn, bkgd_colorIn, bkgd_gammaIn);
 
    Try
    {
@@ -5603,23 +7202,14 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
       d.pm->modifications = NULL;
       gamma_modification_init(&gamma_mod, d.pm, d.file_gamma);
       srgb_modification_init(&srgb_mod, d.pm, 127 /*delete*/);
-      sbit_modification_init(&sbit_mod, d.pm, d.sbit);
+      if (d.sbit > 0)
+         sbit_modification_init(&sbit_mod, d.pm, d.sbit);
 
       modification_reset(d.pm->modifications);
 
       /* Get a png_struct for writing the image. */
       pp = set_modifier_for_read(d.pm, &pi, d.this.id, name);
-
-      /* Set up gamma processing. */
-#ifdef PNG_FLOATING_POINT_SUPPORTED
-      png_set_gamma(pp, d.screen_gamma, d.file_gamma);
-#else
-      {
-         png_fixed_point s = floor(d.screen_gamma*100000+.5);
-         png_fixed_point f = floor(d.file_gamma*100000+.5);
-         png_set_gamma_fixed(pp, s, f);
-      }
-#endif
+      standard_palette_init(&d.this);
 
       /* Introduce the correct read function. */
       if (d.pm->this.progressive)
@@ -5642,16 +7232,17 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
          /* Process the 'info' requirements. Only one image is generated */
          gamma_info_imp(&d, pp, pi);
 
-         sequential_row(&d.this, pp, pi, NULL, d.this.ps->image);
+         sequential_row(&d.this, pp, pi, -1, 0);
 
-         gamma_image_validate(&d, pp, pi, d.this.ps->image);
+         if (!d.this.speed)
+            gamma_image_validate(&d, pp, pi);
       }
 
       modifier_reset(d.pm);
 
-      if (d.pm->log && !d.threshold_test && !d.speed)
+      if (d.pm->log && !d.threshold_test && !d.this.speed)
          fprintf(stderr, "%d bit %s %s: max error %f (%.2g, %2g%%)\n",
-            d.this.bit_depth, colour_types[d.this.colour_type], d.name,
+            d.this.bit_depth, colour_types[d.this.colour_type], name,
             d.maxerrout, d.maxerrabs, 100*d.maxerrpc);
 
       /* Log the summary values too. */
@@ -5713,6 +7304,12 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn,
             png_error(pp, "bad bit depth (internal: 2)");
          }
       }
+
+      else if (d.this.colour_type == 3)
+      {
+         if (d.maxerrout > d.pm->error_indexed)
+            d.pm->error_indexed = d.maxerrout;
+      }
    }
 
    Catch(fault)
@@ -5730,9 +7327,11 @@ static void gamma_threshold_test(png_modifier *pm, png_byte colour_type,
    pos = safecat(name, sizeof name, pos, "/");
    pos = safecatd(name, sizeof name, pos, screen_gamma, 3);
 
-   (void)gamma_test(pm, colour_type, bit_depth, interlace_type, file_gamma,
-      screen_gamma, bit_depth, 1, name, 0 /*speed*/, 0 /*no input precision*/,
-      0 /*no strip16*/);
+   (void)gamma_test(pm, colour_type, bit_depth, 0/*palette*/, interlace_type,
+      file_gamma, screen_gamma, 0/*sBIT*/, 1/*threshold test*/, name,
+      0 /*no input precision*/,
+      0 /*no scale16*/, 0 /*no expand16*/, 0 /*no background*/, 0 /*hence*/,
+      0 /*no background gamma*/);
 }
 
 static void
@@ -5740,8 +7339,14 @@ perform_gamma_threshold_tests(png_modifier *pm)
 {
    png_byte colour_type = 0;
    png_byte bit_depth = 0;
+   int palette_number = 0;
 
-   while (next_format(&colour_type, &bit_depth))
+   /* Don't test more than one instance of each palette - it's pointless, in
+    * fact this test is somewhat excessive since libpng doesn't make this
+    * decision based on colour type or bit depth!
+    */
+   while (next_format(&colour_type, &bit_depth, &palette_number))
+      if (palette_number == 0)
    {
       double test_gamma = 1.0;
       while (test_gamma >= .4)
@@ -5765,14 +7370,15 @@ perform_gamma_threshold_tests(png_modifier *pm)
 
 static void gamma_transform_test(png_modifier *pm,
    PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth,
+   PNG_CONST int palette_number,
    PNG_CONST int interlace_type, PNG_CONST double file_gamma,
-   PNG_CONST double screen_gamma, PNG_CONST png_byte sbit, PNG_CONST int speed,
-   PNG_CONST int use_input_precision, PNG_CONST int strip16)
+   PNG_CONST double screen_gamma, PNG_CONST png_byte sbit,
+   PNG_CONST int use_input_precision, PNG_CONST int scale16)
 {
    size_t pos = 0;
    char name[64];
 
-   if (sbit != bit_depth)
+   if (sbit != bit_depth && sbit != 0)
    {
       pos = safecat(name, sizeof name, pos, "sbit(");
       pos = safecatn(name, sizeof name, pos, sbit);
@@ -5782,34 +7388,33 @@ static void gamma_transform_test(png_modifier *pm,
    else
       pos = safecat(name, sizeof name, pos, "gamma ");
 
-   if (strip16)
+   if (scale16)
       pos = safecat(name, sizeof name, pos, "16to8 ");
 
    pos = safecatd(name, sizeof name, pos, file_gamma, 3);
    pos = safecat(name, sizeof name, pos, "->");
    pos = safecatd(name, sizeof name, pos, screen_gamma, 3);
 
-   gamma_test(pm, colour_type, bit_depth, interlace_type, file_gamma,
-      screen_gamma, sbit, 0, name, speed, use_input_precision, strip16);
+   gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type,
+      file_gamma, screen_gamma, sbit, 0, name, use_input_precision,
+      scale16, pm->test_gamma_expand16, 0 , 0, 0);
 }
 
-static void perform_gamma_transform_tests(png_modifier *pm, int speed)
+static void perform_gamma_transform_tests(png_modifier *pm)
 {
    png_byte colour_type = 0;
    png_byte bit_depth = 0;
+   int palette_number = 0;
 
-   /* Ignore palette images - the gamma correction happens on the palette entry,
-    * haven't got the tests for this yet.
-    */
-   while (next_format(&colour_type, &bit_depth)) if (colour_type != 3)
+   while (next_format(&colour_type, &bit_depth, &palette_number))
    {
       unsigned int i, j;
 
       for (i=0; i<pm->ngammas; ++i) for (j=0; j<pm->ngammas; ++j) if (i != j)
       {
-         gamma_transform_test(pm, colour_type, bit_depth, pm->interlace_type,
-            1/pm->gammas[i], pm->gammas[j], bit_depth, speed,
-            pm->use_input_precision, 0 /*do not strip16*/);
+         gamma_transform_test(pm, colour_type, bit_depth, palette_number,
+            pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/,
+            pm->use_input_precision, 0 /*do not scale16*/);
 
          if (fail(pm))
             return;
@@ -5817,55 +7422,41 @@ static void perform_gamma_transform_tests(png_modifier *pm, int speed)
    }
 }
 
-static void perform_gamma_sbit_tests(png_modifier *pm, int speed)
+static void perform_gamma_sbit_tests(png_modifier *pm)
 {
    png_byte sbit;
 
    /* The only interesting cases are colour and grayscale, alpha is ignored here
-    * for overall speed.  Only bit depths 8 and 16 are tested.
+    * for overall speed.  Only bit depths where sbit is less than the bit depth
+    * are tested.
     */
    for (sbit=pm->sbitlow; sbit<(1<<READ_BDHI); ++sbit)
    {
-      unsigned int i, j;
-
-      for (i=0; i<pm->ngammas; ++i)
-      {
-         for (j=0; j<pm->ngammas; ++j)
-         {
-            if (i != j)
-            {
-               if (sbit < 8)
-               {
-                  gamma_transform_test(pm, 0, 8, pm->interlace_type,
-                      1/pm->gammas[i], pm->gammas[j], sbit, speed,
-                      pm->use_input_precision_sbit, 0 /*strip16*/);
+      png_byte colour_type, bit_depth;
+      int npalette;
 
-                  if (fail(pm))
-                     return;
+      colour_type = bit_depth = 0;
+      npalette = 0;
 
-                  gamma_transform_test(pm, 2, 8, pm->interlace_type,
-                      1/pm->gammas[i], pm->gammas[j], sbit, speed,
-                      pm->use_input_precision_sbit, 0 /*strip16*/);
-
-                  if (fail(pm))
-                     return;
-               }
-
-#ifdef DO_16BIT
-               gamma_transform_test(pm, 0, 16, pm->interlace_type,
-                   1/pm->gammas[i], pm->gammas[j], sbit, speed,
-                   pm->use_input_precision_sbit, 0 /*strip16*/);
+      while (next_format(&colour_type, &bit_depth, &npalette))
+         if ((colour_type & PNG_COLOR_MASK_ALPHA) == 0 &&
+            ((colour_type == 3 && sbit < 8) ||
+            (colour_type != 3 && sbit < bit_depth)))
+      {
+         unsigned int i;
 
-               if (fail(pm))
-                  return;
+         for (i=0; i<pm->ngammas; ++i)
+         {
+            unsigned int j;
 
-               gamma_transform_test(pm, 2, 16, pm->interlace_type,
-                   1/pm->gammas[i], pm->gammas[j], sbit, speed,
-                   pm->use_input_precision_sbit, 0 /*strip16*/);
+            for (j=0; j<pm->ngammas; ++j) if (i != j)
+            {
+               gamma_transform_test(pm, colour_type, bit_depth, npalette,
+                  pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
+                  sbit, pm->use_input_precision_sbit, 0 /*scale16*/);
 
                if (fail(pm))
                   return;
-#endif
             }
          }
       }
@@ -5873,10 +7464,11 @@ static void perform_gamma_sbit_tests(png_modifier *pm, int speed)
 }
 
 /* Note that this requires a 16 bit source image but produces 8 bit output, so
- * we only need the 16bit write support.
+ * we only need the 16bit write support, but the 16 bit images are only
+ * generated if DO_16BIT is defined.
  */
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-static void perform_gamma_strip16_tests(png_modifier *pm, int speed)
+#ifdef DO_16BIT
+static void perform_gamma_scale16_tests(png_modifier *pm)
 {
 #  ifndef PNG_MAX_GAMMA_8
 #     define PNG_MAX_GAMMA_8 11
@@ -5897,30 +7489,30 @@ static void perform_gamma_strip16_tests(png_modifier *pm, int speed)
          if (i != j &&
              fabs(pm->gammas[j]/pm->gammas[i]-1) >= PNG_GAMMA_THRESHOLD)
          {
-            gamma_transform_test(pm, 0, 16, pm->interlace_type, 1/pm->gammas[i],
-                pm->gammas[j], PNG_MAX_GAMMA_8, speed,
-                pm->use_input_precision_16to8, 1 /*strip16*/);
+            gamma_transform_test(pm, 0, 16, 0, pm->interlace_type,
+               1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8,
+               pm->use_input_precision_16to8, 1 /*scale16*/);
 
             if (fail(pm))
                return;
 
-            gamma_transform_test(pm, 2, 16, pm->interlace_type, 1/pm->gammas[i],
-                pm->gammas[j], PNG_MAX_GAMMA_8, speed,
-                pm->use_input_precision_16to8, 1 /*strip16*/);
+            gamma_transform_test(pm, 2, 16, 0, pm->interlace_type,
+               1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8,
+               pm->use_input_precision_16to8, 1 /*scale16*/);
 
             if (fail(pm))
                return;
 
-            gamma_transform_test(pm, 4, 16, pm->interlace_type, 1/pm->gammas[i],
-                pm->gammas[j], PNG_MAX_GAMMA_8, speed,
-                pm->use_input_precision_16to8, 1 /*strip16*/);
+            gamma_transform_test(pm, 4, 16, 0, pm->interlace_type,
+               1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8,
+               pm->use_input_precision_16to8, 1 /*scale16*/);
 
             if (fail(pm))
                return;
 
-            gamma_transform_test(pm, 6, 16, pm->interlace_type, 1/pm->gammas[i],
-                pm->gammas[j], PNG_MAX_GAMMA_8, speed,
-                pm->use_input_precision_16to8, 1 /*strip16*/);
+            gamma_transform_test(pm, 6, 16, 0, pm->interlace_type,
+               1/pm->gammas[i], pm->gammas[j], PNG_MAX_GAMMA_8,
+               pm->use_input_precision_16to8, 1 /*scale16*/);
 
             if (fail(pm))
                return;
@@ -5930,11 +7522,201 @@ static void perform_gamma_strip16_tests(png_modifier *pm, int speed)
 }
 #endif /* 16 to 8 bit conversion */
 
+#if defined PNG_READ_BACKGROUND_SUPPORTED ||\
+   defined PNG_READ_ALPHA_MODE_SUPPORTED
+static void gamma_composition_test(png_modifier *pm,
+   PNG_CONST png_byte colour_type, PNG_CONST png_byte bit_depth,
+   PNG_CONST int palette_number,
+   PNG_CONST int interlace_type, PNG_CONST double file_gamma,
+   PNG_CONST double screen_gamma,
+   PNG_CONST int use_input_precision, PNG_CONST int do_background,
+   PNG_CONST int expand_16)
+{
+   size_t pos = 0;
+   png_const_charp base;
+   double bg;
+   char name[128];
+   png_color_16 background;
+
+   /* Make up a name and get an appropriate background gamma value. */
+   switch (do_background)
+   {
+      default:
+         base = "";
+         bg = 4; /* should not be used */
+         break;
+      case PNG_BACKGROUND_GAMMA_SCREEN:
+         base = " bckg(Screen):";
+         bg = 1/screen_gamma;
+         break;
+      case PNG_BACKGROUND_GAMMA_FILE:
+         base = " bckg(File):";
+         bg = file_gamma;
+         break;
+      case PNG_BACKGROUND_GAMMA_UNIQUE:
+         base = " bckg(Unique):";
+         /* This tests the handling of a unique value, the math is such that the
+          * value tends to be <1, but is neither screen nor file (even if they
+          * match!)
+          */
+         bg = (file_gamma + screen_gamma) / 3;
+         break;
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_PNG:
+         base = " alpha(PNG)";
+         bg = 4; /* should not be used */
+         break;
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD:
+         base = " alpha(Porter-Duff)";
+         bg = 4; /* should not be used */
+         break;
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED:
+         base = " alpha(Optimized)";
+         bg = 4; /* should not be used */
+         break;
+      case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN:
+         base = " alpha(Broken)";
+         bg = 4; /* should not be used */
+         break;
+#endif
+   }
+
+   /* Use random background values - the background is always presented in the
+    * output space (8 or 16 bit components).
+    */
+   if (expand_16 || bit_depth == 16)
+   {
+      png_uint_32 r = random_32();
+
+      background.red = (png_uint_16)r;
+      background.green = (png_uint_16)(r >> 16);
+      r = random_32();
+      background.blue = (png_uint_16)r;
+      background.gray = (png_uint_16)(r >> 16);
+   }
+
+   else /* 8 bit colors */
+   {
+      png_uint_32 r = random_32();
+
+      background.red = (png_byte)r;
+      background.green = (png_byte)(r >> 8);
+      background.blue = (png_byte)(r >> 16);
+      background.gray = (png_byte)(r >> 24);
+   }
+
+   background.index = 193; /* rgb(193,193,193) to detect errors */
+   if (!(colour_type & PNG_COLOR_MASK_COLOR))
+   {
+      /* Grayscale input, we do not convert to RGB (TBD), so we must set the
+       * background to gray - else libpng seems to fail.
+       */
+      background.red = background.green = background.blue = background.gray;
+   }
+
+   pos = safecat(name, sizeof name, pos, "gamma ");
+   pos = safecatd(name, sizeof name, pos, file_gamma, 3);
+   pos = safecat(name, sizeof name, pos, "->");
+   pos = safecatd(name, sizeof name, pos, screen_gamma, 3);
+
+   pos = safecat(name, sizeof name, pos, base);
+   if (do_background < ALPHA_MODE_OFFSET)
+   {
+      /* Include the background color and gamma in the name: */
+      pos = safecat(name, sizeof name, pos, "(");
+      /* This assumes no expand gray->rgb - the current code won't handle that!
+       */
+      if (colour_type & PNG_COLOR_MASK_COLOR)
+      {
+         pos = safecatn(name, sizeof name, pos, background.red);
+         pos = safecat(name, sizeof name, pos, ",");
+         pos = safecatn(name, sizeof name, pos, background.green);
+         pos = safecat(name, sizeof name, pos, ",");
+         pos = safecatn(name, sizeof name, pos, background.blue);
+      }
+      else
+         pos = safecatn(name, sizeof name, pos, background.gray);
+      pos = safecat(name, sizeof name, pos, ")^");
+      pos = safecatd(name, sizeof name, pos, bg, 3);
+   }
+
+   gamma_test(pm, colour_type, bit_depth, palette_number, interlace_type,
+      file_gamma, screen_gamma, 0/*sBIT*/, 0, name, use_input_precision,
+      0/*strip 16*/, expand_16, do_background, &background, bg);
+}
+
+
+static void
+perform_gamma_composition_tests(png_modifier *pm, int do_background,
+   int expand_16)
+{
+   png_byte colour_type = 0;
+   png_byte bit_depth = 0;
+   int palette_number = 0;
+
+   /* Skip the non-alpha cases - there is no setting of a transparency colour at
+    * present.
+    */
+   while (next_format(&colour_type, &bit_depth, &palette_number))
+      if ((colour_type & PNG_COLOR_MASK_ALPHA) != 0)
+   {
+      unsigned int i, j;
+
+      /* Don't skip the i==j case here - it's relevant. */
+      for (i=0; i<pm->ngammas; ++i) for (j=0; j<pm->ngammas; ++j)
+      {
+         gamma_composition_test(pm, colour_type, bit_depth, palette_number,
+            pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
+            pm->use_input_precision, do_background, expand_16);
+
+         if (fail(pm))
+            return;
+      }
+   }
+}
+#endif /* READ_BACKGROUND || READ_ALPHA_MODE */
+
+static void
+init_gamma_errors(png_modifier *pm)
+{
+   pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 = 0;
+   pm->error_color_8 = 0;
+   pm->error_indexed = 0;
+   pm->error_gray_16 = pm->error_color_16 = 0;
+}
+
 static void
-perform_gamma_test(png_modifier *pm, int speed, int summary)
+summarize_gamma_errors(png_modifier *pm, png_const_charp who, int low_bit_depth)
 {
+   if (who)
+      printf("Gamma correction with %s:\n", who);
+
+   if (low_bit_depth)
+   {
+      printf("  2 bit gray:  %.5f\n", pm->error_gray_2);
+      printf("  4 bit gray:  %.5f\n", pm->error_gray_4);
+      printf("  8 bit gray:  %.5f\n", pm->error_gray_8);
+      printf("  8 bit color: %.5f\n", pm->error_color_8);
+      printf("  indexed:     %.5f\n", pm->error_indexed);
+   }
+
+#ifdef DO_16BIT
+   printf(" 16 bit gray:  %.5f\n", pm->error_gray_16);
+   printf(" 16 bit color: %.5f\n", pm->error_color_16);
+#endif
+}
+
+static void
+perform_gamma_test(png_modifier *pm, int summary)
+{
+   /*TODO: remove this*/
+   /* Save certain values for the temporary overrides below. */
+   unsigned int calculations_use_input_precision =
+      pm->calculations_use_input_precision;
+   double maxout8 = pm->maxout8;
+
    /* First some arbitrary no-transform tests: */
-   if (!speed && pm->test_gamma_threshold)
+   if (!pm->this.speed && pm->test_gamma_threshold)
    {
       perform_gamma_threshold_tests(pm);
 
@@ -5945,7 +7727,15 @@ perform_gamma_test(png_modifier *pm, int speed, int summary)
    /* Now some real transforms. */
    if (pm->test_gamma_transform)
    {
-      perform_gamma_transform_tests(pm, speed);
+      init_gamma_errors(pm);
+      /*TODO: remove this.  Necessary because the current libpng
+       * implementation works in 8 bits:
+       */
+      if (pm->test_gamma_expand16)
+         pm->calculations_use_input_precision = 1;
+      perform_gamma_transform_tests(pm);
+      if (!calculations_use_input_precision)
+         pm->calculations_use_input_precision = 0;
 
       if (summary)
       {
@@ -5962,50 +7752,26 @@ perform_gamma_test(png_modifier *pm, int speed, int summary)
          printf("For performance reasons the value for 16 bit formats\n");
          printf("increases when the image file includes an sBIT chunk.\n\n");
 
-         printf("  2 bit gray:  %.5f\n", pm->error_gray_2);
-         printf("  4 bit gray:  %.5f\n", pm->error_gray_4);
-         printf("  8 bit gray:  %.5f\n", pm->error_gray_8);
-         printf("  8 bit color: %.5f\n", pm->error_color_8);
-#ifdef DO_16BIT
-         printf(" 16 bit gray:  %.5f\n", pm->error_gray_16);
-         printf(" 16 bit color: %.5f\n", pm->error_color_16);
-#endif
+         summarize_gamma_errors(pm, 0/*who*/, 1);
       }
    }
 
    /* The sbit tests produce much larger errors: */
    if (pm->test_gamma_sbit)
    {
-      pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 =
-      pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0;
-      perform_gamma_sbit_tests(pm, speed);
+      init_gamma_errors(pm);
+      perform_gamma_sbit_tests(pm);
 
       if (summary)
-      {
-         printf("Gamma correction with sBIT:\n");
-
-         if (pm->sbitlow < 8U)
-         {
-            printf("  2 bit gray:  %.5f\n", pm->error_gray_2);
-            printf("  4 bit gray:  %.5f\n", pm->error_gray_4);
-            printf("  8 bit gray:  %.5f\n", pm->error_gray_8);
-            printf("  8 bit color: %.5f\n", pm->error_color_8);
-         }
-
-   #ifdef DO_16BIT
-         printf(" 16 bit gray:  %.5f\n", pm->error_gray_16);
-         printf(" 16 bit color: %.5f\n", pm->error_color_16);
-   #endif
-      }
+         summarize_gamma_errors(pm, "sBIT", pm->sbitlow < 8U);
    }
 
-#ifdef PNG_READ_16_TO_8_SUPPORTED
-   if (pm->test_gamma_strip16)
+#ifdef DO_16BIT /* Should be READ_16BIT_SUPPORTED */
+   if (pm->test_gamma_scale16)
    {
       /* The 16 to 8 bit strip operations: */
-      pm->error_gray_2 = pm->error_gray_4 = pm->error_gray_8 =
-      pm->error_gray_16 = pm->error_color_8 = pm->error_color_16 = 0;
-      perform_gamma_strip16_tests(pm, speed);
+      init_gamma_errors(pm);
+      perform_gamma_scale16_tests(pm);
 
       if (summary)
       {
@@ -6015,7 +7781,57 @@ perform_gamma_test(png_modifier *pm, int speed, int summary)
       }
    }
 #endif
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+   if (pm->test_gamma_background)
+   {
+      init_gamma_errors(pm);
+
+      /*TODO: remove this.  Necessary because the current libpng
+       * implementation works in 8 bits:
+       */
+      if (pm->test_gamma_expand16)
+      {
+         pm->calculations_use_input_precision = 1;
+         pm->maxout8 = .499; /* because the 16 bit background is smashed */
+      }
+      perform_gamma_composition_tests(pm, PNG_BACKGROUND_GAMMA_UNIQUE,
+         pm->test_gamma_expand16);
+      if (!calculations_use_input_precision)
+         pm->calculations_use_input_precision = 0;
+      pm->maxout8 = maxout8;
+
+      if (summary)
+         summarize_gamma_errors(pm, "background", 1);
+   }
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+   if (pm->test_gamma_alpha_mode)
+   {
+      int do_background;
+
+      init_gamma_errors(pm);
+
+      /*TODO: remove this.  Necessary because the current libpng
+       * implementation works in 8 bits:
+       */
+      if (pm->test_gamma_expand16)
+         pm->calculations_use_input_precision = 1;
+      for (do_background = ALPHA_MODE_OFFSET + PNG_ALPHA_STANDARD;
+         do_background <= ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN && !fail(pm);
+         ++do_background)
+         perform_gamma_composition_tests(pm, do_background,
+            pm->test_gamma_expand16);
+      if (!calculations_use_input_precision)
+         pm->calculations_use_input_precision = 0;
+
+      if (summary)
+         summarize_gamma_errors(pm, "alpha mode", 1);
+   }
+#endif
 }
+#endif /* PNG_READ_GAMMA_SUPPORTED */
 
 /* INTERLACE MACRO VALIDATION */
 /* This is copied verbatim from the specification, it is simply the pass
@@ -6367,6 +8183,7 @@ perform_interlace_macro_validation(void)
 int main(int argc, PNG_CONST char **argv)
 {
    volatile int summary = 1;  /* Print the error summary at the end */
+   volatile int memstats = 0; /* Print memory statistics at the end */
 
    /* Create the given output file on success: */
    PNG_CONST char *volatile touch = NULL;
@@ -6379,24 +8196,24 @@ int main(int argc, PNG_CONST char **argv)
    static double
       gammas[]={2.2, 1.0, 2.2/1.45, 1.8, 1.5, 2.4, 2.5, 2.62, 2.9};
 
+   /* This records the command and arguments: */
+   size_t cp = 0;
+   char command[1024];
+
    png_modifier pm;
    context(&pm.this, fault);
 
    modifier_init(&pm);
 
    /* Preallocate the image buffer, because we know how big it needs to be,
-    * note that, for testing purposes, it is deliberately mis-aligned.
+    * note that, for testing purposes, it is deliberately mis-aligned by tag
+    * bytes either side.  All rows have an additional five bytes of padding for
+    * overwrite checking.
     */
-   pm.this.image = malloc(2*TRANSFORM_IMAGEMAX+1);
+   store_ensure_image(&pm.this, NULL, 2, TRANSFORM_ROWMAX, TRANSFORM_HEIGHTMAX);
 
-   if (pm.this.image != NULL)
-   {
-      /* Ignore OOM at this point - the 'ensure' routine above will allocate
-       * the array appropriately.
-       */
-      ++(pm.this.image);
-      pm.this.cb_image = 2*TRANSFORM_IMAGEMAX;
-   }
+   /* Don't give argv[0], it's normally some horrible libtool string: */
+   cp = safecat(command, sizeof command, cp, "pngvalid");
 
    /* Default to error on warning: */
    pm.this.treat_warnings_as_errors = 1;
@@ -6405,7 +8222,13 @@ int main(int argc, PNG_CONST char **argv)
    pm.gammas = gammas;
    pm.ngammas = 0; /* default to off */
    pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
-   pm.use_input_precision_16to8 = 1U; /* Because of the way libpng does it */
+   /* The following allows results to pass if they correspond to anything in the
+    * transformed range [input-.5,input+.5]; this is is required because of the
+    * way libpng treates the 16_TO_8 flag when building the gamma tables.
+    *
+    * TODO: review this
+    */
+   pm.use_input_precision_16to8 = 1U;
 
    /* Some default values (set the behavior for 'make check' here).
     * These values simply control the maximum error permitted in the gamma
@@ -6416,9 +8239,11 @@ int main(int argc, PNG_CONST char **argv)
     */
    pm.maxout8 = .1;     /* Arithmetic error in *encoded* value */
    pm.maxabs8 = .00005; /* 1/20000 */
+   pm.maxcalc8 = .004;  /* +/-1 in 8 bits for compose errors */
    pm.maxpc8 = .499;    /* I.e., .499% fractional error */
    pm.maxout16 = .499;  /* Error in *encoded* value */
    pm.maxabs16 = .00005;/* 1/20000 */
+   pm.maxcalc16 =.000015;/* +/-1 in 16 bits for compose errors */
 
    /* NOTE: this is a reasonable perceptual limit. We assume that humans can
     * perceive light level differences of 1% over a 100:1 range, so we need to
@@ -6433,7 +8258,13 @@ int main(int argc, PNG_CONST char **argv)
    /* Now parse the command line options. */
    while (--argc >= 1)
    {
-      if (strcmp(*++argv, "-v") == 0)
+      int catmore = 0; /* Set if the argument has an argument. */
+
+      /* Record each argument for posterity: */
+      cp = safecat(command, sizeof command, cp, " ");
+      cp = safecat(command, sizeof command, cp, *++argv);
+
+      if (strcmp(*argv, "-v") == 0)
          pm.this.verbose = 1;
 
       else if (strcmp(*argv, "-l") == 0)
@@ -6447,7 +8278,10 @@ int main(int argc, PNG_CONST char **argv)
 
       else if (strcmp(*argv, "--speed") == 0)
          pm.this.speed = 1, pm.ngammas = (sizeof gammas)/(sizeof gammas[0]),
-            pm.test_standard = 0;
+            pm.test_standard = 0, summary = 0;
+
+      else if (strcmp(*argv, "--memory") == 0)
+         memstats = 1;
 
       else if (strcmp(*argv, "--size") == 0)
          pm.test_size = 1;
@@ -6467,6 +8301,7 @@ int main(int argc, PNG_CONST char **argv)
       else if (strcmp(*argv, "--notransform") == 0)
          pm.test_transform = 0;
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
       else if (strncmp(*argv, "--transform-disable=",
          sizeof "--transform-disable") == 0)
          {
@@ -6480,6 +8315,7 @@ int main(int argc, PNG_CONST char **argv)
          pm.test_transform = 1;
          transform_enable(*argv + sizeof "--transform-enable");
          }
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
       else if (strcmp(*argv, "--gamma") == 0)
          {
@@ -6488,7 +8324,9 @@ int main(int argc, PNG_CONST char **argv)
          pm.test_gamma_threshold = 1;
          pm.test_gamma_transform = 1;
          pm.test_gamma_sbit = 1;
-         pm.test_gamma_strip16 = 1;
+         pm.test_gamma_scale16 = 1;
+         pm.test_gamma_background = 1;
+         pm.test_gamma_alpha_mode = 1;
          }
 
       else if (strcmp(*argv, "--nogamma") == 0)
@@ -6513,10 +8351,31 @@ int main(int argc, PNG_CONST char **argv)
          pm.test_gamma_sbit = 0;
 
       else if (strcmp(*argv, "--gamma-16-to-8") == 0)
-         pm.ngammas = 2U, pm.test_gamma_strip16 = 1;
+         pm.ngammas = 2U, pm.test_gamma_scale16 = 1;
 
       else if (strcmp(*argv, "--nogamma-16-to-8") == 0)
-         pm.test_gamma_strip16 = 0;
+         pm.test_gamma_scale16 = 0;
+
+      else if (strcmp(*argv, "--gamma-background") == 0)
+         pm.ngammas = 2U, pm.test_gamma_background = 1;
+
+      else if (strcmp(*argv, "--nogamma-background") == 0)
+         pm.test_gamma_background = 0;
+
+      else if (strcmp(*argv, "--gamma-alpha-mode") == 0)
+         pm.ngammas = 2U, pm.test_gamma_alpha_mode = 1;
+
+      else if (strcmp(*argv, "--nogamma-alpha-mode") == 0)
+         pm.test_gamma_alpha_mode = 0;
+
+      else if (strcmp(*argv, "--expand16") == 0)
+         pm.test_gamma_expand16 = 1;
+
+      else if (strcmp(*argv, "--noexpand16") == 0)
+         pm.test_gamma_expand16 = 0;
+
+      else if (strcmp(*argv, "--more-gammas") == 0)
+         pm.ngammas = 3U;
 
       else if (strcmp(*argv, "--all-gammas") == 0)
          pm.ngammas = (sizeof gammas)/(sizeof gammas[0]);
@@ -6527,32 +8386,51 @@ int main(int argc, PNG_CONST char **argv)
       else if (strcmp(*argv, "--interlace") == 0)
          pm.interlace_type = PNG_INTERLACE_ADAM7;
 
-      else if (argc >= 1 && strcmp(*argv, "--sbitlow") == 0)
-         --argc, pm.sbitlow = (png_byte)atoi(*++argv);
+      else if (strcmp(*argv, "--use-input-precision") == 0)
+         pm.use_input_precision = 1;
+
+      else if (strcmp(*argv, "--calculations-use-input-precision") == 0)
+         pm.calculations_use_input_precision = 1;
+
+      else if (strcmp(*argv, "--assume-16-bit-calculations") == 0)
+         pm.assume_16_bit_calculations = 1;
 
-      else if (argc >= 1 && strcmp(*argv, "--touch") == 0)
-         --argc, touch = *++argv;
+      else if (strcmp(*argv, "--calculations-follow-bit-depth") == 0)
+         pm.calculations_use_input_precision =
+            pm.assume_16_bit_calculations = 0;
 
-      else if (argc >= 1 && strncmp(*argv, "--max", 4) == 0)
+      else if (argc > 1 && strcmp(*argv, "--sbitlow") == 0)
+         --argc, pm.sbitlow = (png_byte)atoi(*++argv), catmore = 1;
+
+      else if (argc > 1 && strcmp(*argv, "--touch") == 0)
+         --argc, touch = *++argv, catmore = 1;
+
+      else if (argc > 1 && strncmp(*argv, "--max", 5) == 0)
       {
          --argc;
 
-         if (strcmp(4+*argv, "abs8") == 0)
+         if (strcmp(5+*argv, "abs8") == 0)
             pm.maxabs8 = atof(*++argv);
 
-         else if (strcmp(4+*argv, "abs16") == 0)
+         else if (strcmp(5+*argv, "abs16") == 0)
             pm.maxabs16 = atof(*++argv);
 
-         else if (strcmp(4+*argv, "out8") == 0)
+         else if (strcmp(5+*argv, "calc8") == 0)
+            pm.maxcalc8 = atof(*++argv);
+
+         else if (strcmp(5+*argv, "calc16") == 0)
+            pm.maxcalc16 = atof(*++argv);
+
+         else if (strcmp(5+*argv, "out8") == 0)
             pm.maxout8 = atof(*++argv);
 
-         else if (strcmp(4+*argv, "out16") == 0)
+         else if (strcmp(5+*argv, "out16") == 0)
             pm.maxout16 = atof(*++argv);
 
-         else if (strcmp(4+*argv, "pc8") == 0)
+         else if (strcmp(5+*argv, "pc8") == 0)
             pm.maxpc8 = atof(*++argv);
 
-         else if (strcmp(4+*argv, "pc16") == 0)
+         else if (strcmp(5+*argv, "pc16") == 0)
             pm.maxpc16 = atof(*++argv);
 
          else
@@ -6560,13 +8438,27 @@ int main(int argc, PNG_CONST char **argv)
             fprintf(stderr, "pngvalid: %s: unknown 'max' option\n", *argv);
             exit(1);
          }
+
+         catmore = 1;
       }
 
+      else if (strcmp(*argv, "--log8") == 0)
+         --argc, pm.log8 = atof(*++argv), catmore = 1;
+
+      else if (strcmp(*argv, "--log16") == 0)
+         --argc, pm.log16 = atof(*++argv), catmore = 1;
+
       else
       {
          fprintf(stderr, "pngvalid: %s: unknown argument\n", *argv);
          exit(1);
       }
+
+      if (catmore) /* consumed an extra *argv */
+      {
+         cp = safecat(command, sizeof command, cp, " ");
+         cp = safecat(command, sizeof command, cp, *argv);
+      }
    }
 
    /* If pngvalid is run with no arguments default to a reasonable set of the
@@ -6575,20 +8467,28 @@ int main(int argc, PNG_CONST char **argv)
    if (pm.test_standard == 0 && pm.test_size == 0 && pm.test_transform == 0 &&
       pm.ngammas == 0)
    {
+      /* Make this do all the tests done in the test shell scripts with the same
+       * parameters, where possible.  The limitation is that all the progressive
+       * read and interlace stuff has to be done in separate runs, so only the
+       * basic 'standard' and 'size' tests are done.
+       */
       pm.test_standard = 1;
       pm.test_size = 1;
       pm.test_transform = 1;
-      pm.ngammas = 3U;
+      pm.ngammas = 2U;
    }
 
    if (pm.ngammas > 0 &&
       pm.test_gamma_threshold == 0 && pm.test_gamma_transform == 0 &&
-      pm.test_gamma_sbit == 0 && pm.test_gamma_strip16 == 0)
+      pm.test_gamma_sbit == 0 && pm.test_gamma_scale16 == 0 &&
+      pm.test_gamma_background == 0 && pm.test_gamma_alpha_mode == 0)
    {
       pm.test_gamma_threshold = 1;
       pm.test_gamma_transform = 1;
       pm.test_gamma_sbit = 1;
-      pm.test_gamma_strip16 = 1;
+      pm.test_gamma_scale16 = 1;
+      pm.test_gamma_background = 1;
+      pm.test_gamma_alpha_mode = 1;
    }
 
    else if (pm.ngammas == 0)
@@ -6597,7 +8497,9 @@ int main(int argc, PNG_CONST char **argv)
       pm.test_gamma_threshold = 0;
       pm.test_gamma_transform = 0;
       pm.test_gamma_sbit = 0;
-      pm.test_gamma_strip16 = 0;
+      pm.test_gamma_scale16 = 0;
+      pm.test_gamma_background = 0;
+      pm.test_gamma_alpha_mode = 0;
    }
 
    Try
@@ -6609,6 +8511,7 @@ int main(int argc, PNG_CONST char **argv)
       if (pm.test_standard)
       {
          perform_interlace_macro_validation();
+         perform_formatting_test(&pm.this);
          perform_standard_test(&pm);
          perform_error_test(&pm);
       }
@@ -6620,13 +8523,16 @@ int main(int argc, PNG_CONST char **argv)
          perform_size_test(&pm);
       }
 
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
       /* Combinatorial transforms: */
       if (pm.test_transform)
          perform_transform_test(&pm);
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
 
+#ifdef PNG_READ_GAMMA_SUPPORTED
       if (pm.ngammas > 0)
-         perform_gamma_test(&pm, pm.this.speed != 0,
-            summary && !pm.this.speed);
+         perform_gamma_test(&pm, summary);
+#endif
    }
 
    Catch(fault)
@@ -6642,18 +8548,22 @@ int main(int argc, PNG_CONST char **argv)
       exit(1);
    }
 
-   if (summary && !pm.this.speed)
+   if (summary)
    {
-      printf("Results using %s point arithmetic %s\n",
+      printf("%s: %s (%s point arithmetic)\n",
+         (pm.this.nerrors || (pm.this.treat_warnings_as_errors &&
+            pm.this.nwarnings)) ? "FAIL" : "PASS",
+         command,
 #if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || PNG_LIBPNG_VER < 10500
-         "floating",
+         "floating"
 #else
-         "fixed",
+         "fixed"
 #endif
-         (pm.this.nerrors || (pm.this.treat_warnings_as_errors &&
-            pm.this.nwarnings)) ? "(errors)" : (pm.this.nwarnings ?
-               "(warnings)" : "(no errors or warnings)")
-      );
+         );
+   }
+
+   if (memstats)
+   {
       printf("Allocated memory statistics (in bytes):\n"
          "\tread  %lu maximum single, %lu peak, %lu total\n"
          "\twrite %lu maximum single, %lu peak, %lu total\n",
index 9277a951628fd9aef31a13d685cff4b291ddf8a8..d1af9e899fb285428412c469baaa4aa9e87228b0 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Last changed in libpng 1.5.1 [February 3, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -99,8 +99,10 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
          int keep = png_handle_as_unknown(png_ptr, up->name);
 
          if (keep != PNG_HANDLE_CHUNK_NEVER &&
-             up->location && !(up->location & PNG_HAVE_PLTE) &&
+             up->location &&
+             !(up->location & PNG_HAVE_PLTE) &&
              !(up->location & PNG_HAVE_IDAT) &&
+             !(up->location & PNG_AFTER_IDAT) &&
              ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
              (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
          {
@@ -273,8 +275,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
       {
          int keep = png_handle_as_unknown(png_ptr, up->name);
          if (keep != PNG_HANDLE_CHUNK_NEVER &&
-             up->location && (up->location & PNG_HAVE_PLTE) &&
+             up->location &&
+             (up->location & PNG_HAVE_PLTE) &&
              !(up->location & PNG_HAVE_IDAT) &&
+             !(up->location & PNG_AFTER_IDAT) &&
              ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
              (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
          {
@@ -380,7 +384,8 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
       {
          int keep = png_handle_as_unknown(png_ptr, up->name);
          if (keep != PNG_HANDLE_CHUNK_NEVER &&
-             up->location && (up->location & PNG_AFTER_IDAT) &&
+             up->location &&
+             (up->location & PNG_AFTER_IDAT) &&
              ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
              (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
          {
@@ -462,10 +467,9 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    png_structp png_ptr;
 #ifdef PNG_SETJMP_SUPPORTED
 #ifdef USE_FAR_KEYWORD
-   jmp_buf png_jmpbuf;
+   jmp_buf tmp_jmpbuf;
 #endif
 #endif
-   int i;
 
    png_debug(1, "in png_create_write_struct");
 
@@ -489,12 +493,12 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
    encounter a png_error() will longjmp here.  Since the jmpbuf is
    then meaningless we abort instead of returning. */
 #ifdef USE_FAR_KEYWORD
-   if (setjmp(png_jmpbuf))
+   if (setjmp(tmp_jmpbuf))
 #else
    if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */
 #endif
 #ifdef USE_FAR_KEYWORD
-   png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
 #endif
       PNG_ABORT();
 #endif
@@ -504,49 +508,8 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
 #endif /* PNG_USER_MEM_SUPPORTED */
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   if (user_png_ver)
-   {
-      i = 0;
-      do
-      {
-         if (user_png_ver[i] != png_libpng_ver[i])
-            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-      } while (png_libpng_ver[i++]);
-   }
-
-   if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
-   {
-     /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
-      * we must recompile any applications that use any older library version.
-      * For versions after libpng 1.0, we will be compatible, so we need
-      * only check the first digit.
-      */
-     if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
-         (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
-         (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
-     {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-        char msg[80];
-
-        if (user_png_ver)
-        {
-            png_snprintf2(msg, 80,
-                "Application built with libpng-%.20s"
-                " but running with %.20s",
-                user_png_ver,
-                png_libpng_ver);
-            png_warning(png_ptr, msg);
-         }
-#else
-         png_warning(png_ptr,
-             "Incompatible libpng version in application and library");
-#endif
-#ifdef PNG_ERROR_NUMBERS_SUPPORTED
-        png_ptr->flags = 0;
-#endif
-        png_cleanup_needed = 1;
-     }
-   }
+   if (!png_user_version_check(png_ptr, user_png_ver))
+      png_cleanup_needed = 1;
 
    /* Initialize zbuf - compression buffer */
    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
@@ -805,9 +768,11 @@ png_write_row(png_structp png_ptr, png_const_bytep row)
    }
 #endif
 
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
    /* Handle other transformations */
    if (png_ptr->transformations)
       png_do_write_transformations(png_ptr);
+#endif
 
 #ifdef PNG_MNG_FEATURES_SUPPORTED
    /* Write filter_method 64 (intrapixel differencing) only if
@@ -884,8 +849,6 @@ png_write_flush(png_structp png_ptr)
       {
          /* Write the IDAT and reset the zlib output buffer */
          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
-         png_ptr->zstream.next_out = png_ptr->zbuf;
-         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
          wrote_IDAT = 1;
       }
    } while (wrote_IDAT == 1);
@@ -896,8 +859,6 @@ png_write_flush(png_structp png_ptr)
       /* Write the IDAT and reset the zlib output buffer */
       png_write_IDAT(png_ptr, png_ptr->zbuf,
           png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-      png_ptr->zstream.next_out = png_ptr->zbuf;
-      png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
    }
    png_ptr->flush_rows = 0;
    png_flush(png_ptr);
@@ -983,7 +944,9 @@ png_write_destroy(png_structp png_ptr)
    jmp_buf tmp_jmp; /* Save jump buffer */
 #endif
    png_error_ptr error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    png_error_ptr warning_fn;
+#endif
    png_voidp error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    png_free_ptr free_fn;
@@ -992,7 +955,8 @@ png_write_destroy(png_structp png_ptr)
    png_debug(1, "in png_write_destroy");
 
    /* Free any memory zlib uses */
-   deflateEnd(&png_ptr->zstream);
+   if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED)
+      deflateEnd(&png_ptr->zstream);
 
    /* Free our memory.  png_free checks NULL for us. */
    png_free(png_ptr, png_ptr->zbuf);
@@ -1005,10 +969,6 @@ png_write_destroy(png_structp png_ptr)
    png_free(png_ptr, png_ptr->paeth_row);
 #endif
 
-#ifdef PNG_TIME_RFC1123_SUPPORTED
-   png_free(png_ptr, png_ptr->time_buffer);
-#endif
-
 #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
    /* Use this to save a little code space, it doesn't free the filter_costs */
    png_reset_filter_heuristics(png_ptr);
@@ -1018,11 +978,13 @@ png_write_destroy(png_structp png_ptr)
 
 #ifdef PNG_SETJMP_SUPPORTED
    /* Reset structure */
-   png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf));
+   png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
 #endif
 
    error_fn = png_ptr->error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    warning_fn = png_ptr->warning_fn;
+#endif
    error_ptr = png_ptr->error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    free_fn = png_ptr->free_fn;
@@ -1031,14 +993,16 @@ png_write_destroy(png_structp png_ptr)
    png_memset(png_ptr, 0, png_sizeof(png_struct));
 
    png_ptr->error_fn = error_fn;
+#ifdef PNG_WARNINGS_SUPPORTED
    png_ptr->warning_fn = warning_fn;
+#endif
    png_ptr->error_ptr = error_ptr;
 #ifdef PNG_USER_MEM_SUPPORTED
    png_ptr->free_fn = free_fn;
 #endif
 
 #ifdef PNG_SETJMP_SUPPORTED
-   png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
+   png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf));
 #endif
 }
 
@@ -1451,6 +1415,9 @@ png_set_compression_strategy(png_structp png_ptr, int strategy)
    png_ptr->zlib_strategy = strategy;
 }
 
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
 void PNGAPI
 png_set_compression_window_bits(png_structp png_ptr, int window_bits)
 {
@@ -1491,6 +1458,89 @@ png_set_compression_method(png_structp png_ptr, int method)
    png_ptr->zlib_method = method;
 }
 
+/* The following were added to libpng-1.5.4 */
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+void PNGAPI
+png_set_text_compression_level(png_structp png_ptr, int level)
+{
+   png_debug(1, "in png_set_text_compression_level");
+
+   if (png_ptr == NULL)
+      return;
+
+   png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_LEVEL;
+   png_ptr->zlib_text_level = level;
+}
+
+void PNGAPI
+png_set_text_compression_mem_level(png_structp png_ptr, int mem_level)
+{
+   png_debug(1, "in png_set_text_compression_mem_level");
+
+   if (png_ptr == NULL)
+      return;
+
+   png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL;
+   png_ptr->zlib_text_mem_level = mem_level;
+}
+
+void PNGAPI
+png_set_text_compression_strategy(png_structp png_ptr, int strategy)
+{
+   png_debug(1, "in png_set_text_compression_strategy");
+
+   if (png_ptr == NULL)
+      return;
+
+   png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_STRATEGY;
+   png_ptr->zlib_text_strategy = strategy;
+}
+
+/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a
+ * smaller value of window_bits if it can do so safely.
+ */
+void PNGAPI
+png_set_text_compression_window_bits(png_structp png_ptr, int window_bits)
+{
+   if (png_ptr == NULL)
+      return;
+
+   if (window_bits > 15)
+      png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+
+   else if (window_bits < 8)
+      png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
+
+#ifndef WBITS_8_OK
+   /* Avoid libpng bug with 256-byte windows */
+   if (window_bits == 8)
+      {
+        png_warning(png_ptr, "Text compression window is being reset to 512");
+        window_bits = 9;
+      }
+
+#endif
+   png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS;
+   png_ptr->zlib_text_window_bits = window_bits;
+}
+
+void PNGAPI
+png_set_text_compression_method(png_structp png_ptr, int method)
+{
+   png_debug(1, "in png_set_text_compression_method");
+
+   if (png_ptr == NULL)
+      return;
+
+   if (method != 8)
+      png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+
+   png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_METHOD;
+   png_ptr->zlib_text_method = method;
+}
+#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
+/* end of API added to libpng-1.5.4 */
+
 void PNGAPI
 png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
 {
@@ -1557,7 +1607,7 @@ png_write_png(png_structp png_ptr, png_infop info_ptr,
 #endif
 
 #ifdef PNG_WRITE_FILLER_SUPPORTED
-   /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */
+   /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */
    if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER)
       png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
 
index bbf4a25b92e72b9f8400491691c084b480e31ba8..124d708c4a3b99818ce9b0f6b6d97a91d23771e7 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngwtran.c - transforms the data in a row for PNG writers
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -15,6 +15,7 @@
 
 #ifdef PNG_WRITE_SUPPORTED
 
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
 /* Transform the data according to the user's wishes.  The order of
  * transformations is significant.
  */
@@ -45,7 +46,7 @@ png_do_write_transformations(png_structp png_ptr)
 #ifdef PNG_WRITE_FILLER_SUPPORTED
    if (png_ptr->transformations & PNG_FILLER)
       png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1,
-         !(png_ptr->flags & PNG_FILLER_AFTER));
+         !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
 #endif
 
 #ifdef PNG_WRITE_PACKSWAP_SUPPORTED
@@ -563,6 +564,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
    }
 }
 #endif
+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
 
 #ifdef PNG_MNG_FEATURES_SUPPORTED
 /* Undoes intrapixel differencing  */
index 2c35785aa125a2138a069b75801e7449cc27c7c0..3ae5ed4e2f1e18b845a6b96cc1d3ea4ce2e60559 100644 (file)
@@ -1,7 +1,7 @@
 
 /* pngwutil.c - utilities to write a PNG file
  *
- * Last changed in libpng 1.5.0 [January 6, 2011]
+ * Last changed in libpng 1.5.4 [July 7, 2011]
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -192,7 +192,149 @@ png_write_chunk_end(png_structp png_ptr)
    png_write_data(png_ptr, buf, (png_size_t)4);
 }
 
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
+/* Initialize the compressor for the appropriate type of compression. */
+static void
+png_zlib_claim(png_structp png_ptr, png_uint_32 state)
+{
+   if (!(png_ptr->zlib_state & PNG_ZLIB_IN_USE))
+   {
+      /* If already initialized for 'state' do not re-init. */
+      if (png_ptr->zlib_state != state)
+      {
+         int ret = Z_OK;
+         png_const_charp who = "-";
+
+         /* If actually initialized for another state do a deflateEnd. */
+         if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED)
+         {
+            ret = deflateEnd(&png_ptr->zstream);
+            who = "end";
+            png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED;
+         }
+
+         /* zlib itself detects an incomplete state on deflateEnd */
+         if (ret == Z_OK) switch (state)
+         {
+#           ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+               case PNG_ZLIB_FOR_TEXT:
+                  ret = deflateInit2(&png_ptr->zstream,
+                     png_ptr->zlib_text_level, png_ptr->zlib_text_method,
+                     png_ptr->zlib_text_window_bits,
+                     png_ptr->zlib_text_mem_level, png_ptr->zlib_text_strategy);
+                  who = "text";
+                  break;
+#           endif
+
+            case PNG_ZLIB_FOR_IDAT:
+               ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
+                   png_ptr->zlib_method, png_ptr->zlib_window_bits,
+                   png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
+               who = "IDAT";
+               break;
+
+            default:
+               png_error(png_ptr, "invalid zlib state");
+         }
+
+         if (ret == Z_OK)
+            png_ptr->zlib_state = state;
+
+         else /* an error in deflateEnd or deflateInit2 */
+         {
+            size_t pos = 0;
+            char msg[64];
+
+            pos = png_safecat(msg, sizeof msg, pos,
+               "zlib failed to initialize compressor (");
+            pos = png_safecat(msg, sizeof msg, pos, who);
+
+            switch (ret)
+            {
+               case Z_VERSION_ERROR:
+                  pos = png_safecat(msg, sizeof msg, pos, ") version error");
+                  break;
+
+               case Z_STREAM_ERROR:
+                  pos = png_safecat(msg, sizeof msg, pos, ") stream error");
+                  break;
+
+               case Z_MEM_ERROR:
+                  pos = png_safecat(msg, sizeof msg, pos, ") memory error");
+                  break;
+
+               default:
+                  pos = png_safecat(msg, sizeof msg, pos, ") unknown error");
+                  break;
+            }
+
+            png_error(png_ptr, msg);
+         }
+      }
+
+      /* Here on success, claim the zstream: */
+      png_ptr->zlib_state |= PNG_ZLIB_IN_USE;
+   }
+
+   else
+      png_error(png_ptr, "zstream already in use (internal error)");
+}
+
+/* The opposite: release the stream.  It is also reset, this API will warn on
+ * error but will not fail.
+ */
+static void
+png_zlib_release(png_structp png_ptr)
+{
+   if (png_ptr->zlib_state & PNG_ZLIB_IN_USE)
+   {
+      int ret = deflateReset(&png_ptr->zstream);
+
+      png_ptr->zlib_state &= ~PNG_ZLIB_IN_USE;
+
+      if (ret != Z_OK)
+      {
+         png_const_charp err;
+         PNG_WARNING_PARAMETERS(p)
+
+         switch (ret)
+         {
+            case Z_VERSION_ERROR:
+               err = "version";
+               break;
+
+            case Z_STREAM_ERROR:
+               err = "stream";
+               break;
+
+            case Z_MEM_ERROR:
+               err = "memory";
+               break;
+
+            default:
+               err = "unknown";
+               break;
+         }
+
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, ret);
+         png_warning_parameter(p, 2, err);
+
+         if (png_ptr->zstream.msg)
+            err = png_ptr->zstream.msg;
+         else
+            err = "[no zlib message]";
+
+         png_warning_parameter(p, 3, err);
+
+         png_formatted_warning(png_ptr, p,
+            "zlib failed to reset compressor: @1(@2): @3");
+      }
+   }
+
+   else
+      png_warning(png_ptr, "zstream not in use (internal error)");
+}
+
+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
 /* This pair of functions encapsulates the operation of (a) compressing a
  * text string, and (b) issuing it later as a series of chunk data writes.
  * The compression_state structure is shared context for these functions
@@ -220,25 +362,22 @@ png_text_compress(png_structp png_ptr,
    comp->max_output_ptr = 0;
    comp->output_ptr = NULL;
    comp->input = NULL;
-   comp->input_len = 0;
+   comp->input_len = text_len;
 
    /* We may just want to pass the text right through */
    if (compression == PNG_TEXT_COMPRESSION_NONE)
    {
       comp->input = (png_const_bytep)text;
-      comp->input_len = text_len;
       return((int)text_len);
    }
 
    if (compression >= PNG_TEXT_COMPRESSION_LAST)
    {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-      char msg[50];
-      png_snprintf(msg, 50, "Unknown compression type %d", compression);
-      png_warning(png_ptr, msg);
-#else
-      png_warning(png_ptr, "Unknown compression type");
-#endif
+      PNG_WARNING_PARAMETERS(p)
+
+      png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d,
+         compression);
+      png_formatted_warning(png_ptr, p, "Unknown compression type @1");
    }
 
    /* We can't write the chunk until we find out how much data we have,
@@ -255,10 +394,12 @@ png_text_compress(png_structp png_ptr,
     * data, or if the input string is incredibly large (although this
     * wouldn't cause a failure, just a slowdown due to swapping).
     */
+   png_zlib_claim(png_ptr, PNG_ZLIB_FOR_TEXT);
 
    /* Set up the compression buffers */
    /* TODO: the following cast hides a potential overflow problem. */
    png_ptr->zstream.avail_in = (uInt)text_len;
+
    /* NOTE: assume zlib doesn't overwrite the input */
    png_ptr->zstream.next_in = (Bytef *)text;
    png_ptr->zstream.avail_out = png_ptr->zbuf_size;
@@ -418,6 +559,68 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
       return;
    }
 
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
+   if (comp->input_len >= 2 && comp->input_len < 16384)
+   {
+      unsigned int z_cmf;  /* zlib compression method and flags */
+
+      /* Optimize the CMF field in the zlib stream.  This hack of the zlib
+       * stream is compliant to the stream specification.
+       */
+
+      if (comp->num_output_ptr)
+        z_cmf = comp->output_ptr[0][0];
+      else
+        z_cmf = png_ptr->zbuf[0];
+
+      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
+      {
+         unsigned int z_cinfo;
+         unsigned int half_z_window_size;
+         png_size_t uncompressed_text_size = comp->input_len;
+
+         z_cinfo = z_cmf >> 4;
+         half_z_window_size = 1 << (z_cinfo + 7);
+
+         while (uncompressed_text_size <= half_z_window_size &&
+             half_z_window_size >= 256)
+         {
+            z_cinfo--;
+            half_z_window_size >>= 1;
+         }
+
+         z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
+
+         if (comp->num_output_ptr)
+         {
+
+           if (comp->output_ptr[0][0] != z_cmf)
+           {
+              int tmp;
+
+              comp->output_ptr[0][0] = (png_byte)z_cmf;
+              tmp = comp->output_ptr[0][1] & 0xe0;
+              tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;
+              comp->output_ptr[0][1] = (png_byte)tmp;
+           }
+         }
+         else
+         {
+            int tmp;
+
+            png_ptr->zbuf[0] = (png_byte)z_cmf;
+            tmp = png_ptr->zbuf[1] & 0xe0;
+            tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;
+            png_ptr->zbuf[1] = (png_byte)tmp;
+         }
+      }
+
+      else
+         png_error(png_ptr,
+             "Invalid zlib compression method or flags in non-IDAT chunk");
+   }
+#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
+
    /* Write saved output buffers, if any */
    for (i = 0; i < comp->num_output_ptr; i++)
    {
@@ -436,10 +639,9 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
           (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out));
 
    /* Reset zlib for another zTXt/iTXt or image data */
-   deflateReset(&png_ptr->zstream);
-   png_ptr->zstream.data_type = Z_BINARY;
+   png_zlib_release(png_ptr);
 }
-#endif
+#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
 
 /* Write the IHDR chunk, and update the png_struct with the necessary
  * information.  Note that the rest of this code depends upon this
@@ -451,7 +653,6 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
     int interlace_type)
 {
    PNG_IHDR;
-   int ret;
 
    png_byte buf[13]; /* Buffer to store the IHDR info */
 
@@ -632,35 +833,35 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
    if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
       png_ptr->zlib_method = 8;
 
-   ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
-       png_ptr->zlib_method, png_ptr->zlib_window_bits,
-       png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
-
-   if (ret != Z_OK)
-   {
-      if (ret == Z_VERSION_ERROR)
-         png_error(png_ptr,
-            "zlib failed to initialize compressor -- version error");
-
-      if (ret == Z_STREAM_ERROR)
-         png_error(png_ptr,
-             "zlib failed to initialize compressor -- stream error");
+#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
+   if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_STRATEGY))
+      png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY;
 
-      if (ret == Z_MEM_ERROR)
-         png_error(png_ptr,
-             "zlib failed to initialize compressor -- mem error");
+   if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_LEVEL))
+      png_ptr->zlib_text_level = png_ptr->zlib_level;
 
-      png_error(png_ptr, "zlib failed to initialize compressor");
-   }
+   if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL))
+      png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level;
 
-   png_ptr->zstream.next_out = png_ptr->zbuf;
-   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-   /* libpng is not interested in zstream.data_type, so set it
-    * to a predefined value, to avoid its evaluation inside zlib
-    */
-   png_ptr->zstream.data_type = Z_BINARY;
+   if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS))
+      png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits;
 
-   png_ptr->mode = PNG_HAVE_IHDR;
+   if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_METHOD))
+      png_ptr->zlib_text_method = png_ptr->zlib_method;
+#else
+   png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY;
+   png_ptr->zlib_text_level = png_ptr->zlib_level;
+   png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level;
+   png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits;
+   png_ptr->zlib_text_method = png_ptr->zlib_method;
+#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
+#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */
+
+   /* Record that the compressor has not yet been initialized. */
+   png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED;
+
+   png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */
 }
 
 /* Write the palette.  We are careful not to trust png_color to be in the
@@ -745,12 +946,15 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
 
    png_debug(1, "in png_write_IDAT");
 
-   /* Optimize the CMF field in the zlib stream. */
-   /* This hack of the zlib stream is compliant to the stream specification. */
+#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
    if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
        png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
    {
+      /* Optimize the CMF field in the zlib stream.  This hack of the zlib
+       * stream is compliant to the stream specification.
+       */
       unsigned int z_cmf = data[0];  /* zlib compression method and flags */
+
       if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
       {
          /* Avoid memory underflows and multiplication overflows.
@@ -761,11 +965,29 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
          if (length >= 2 &&
              png_ptr->height < 16384 && png_ptr->width < 16384)
          {
+            /* Compute the maximum possible length of the datastream */
+
+            /* Number of pixels, plus for each row a filter byte
+             * and possibly a padding byte, so increase the maximum
+             * size to account for these.
+             */
+            unsigned int z_cinfo;
+            unsigned int half_z_window_size;
             png_uint_32 uncompressed_idat_size = png_ptr->height *
                 ((png_ptr->width *
                 png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
-            unsigned int z_cinfo = z_cmf >> 4;
-            unsigned int half_z_window_size = 1 << (z_cinfo + 7);
+
+            /* If it's interlaced, each block of 8 rows is sent as up to
+             * 14 rows, i.e., 6 additional rows, each with a filter byte
+             * and possibly a padding byte
+             */
+            if (png_ptr->interlaced)
+               uncompressed_idat_size += ((png_ptr->height + 7)/8) *
+                   (png_ptr->bit_depth < 8 ? 12 : 6);
+
+            z_cinfo = z_cmf >> 4;
+            half_z_window_size = 1 << (z_cinfo + 7);
+
             while (uncompressed_idat_size <= half_z_window_size &&
                 half_z_window_size >= 256)
             {
@@ -790,9 +1012,17 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
          png_error(png_ptr,
              "Invalid zlib compression method or flags in IDAT");
    }
+#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */
 
    png_write_chunk(png_ptr, png_IDAT, data, length);
    png_ptr->mode |= PNG_HAVE_IDAT;
+
+   /* Prior to 1.5.4 this code was replicated in every caller (except at the
+    * end, where it isn't technically necessary).  Since this function has
+    * flushed the data we can safely reset the zlib output buffer here.
+    */
+   png_ptr->zstream.next_out = png_ptr->zbuf;
+   png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
 }
 
 /* Write an IEND chunk */
@@ -918,7 +1148,10 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
        (png_size_t)(name_len + 2));
 
    if (profile_len)
+   {
+      comp.input_len = profile_len;
       png_write_compressed_data_out(png_ptr, &comp);
+   }
 
    png_write_chunk_end(png_ptr);
    png_free(png_ptr, new_name);
@@ -1313,15 +1546,11 @@ png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key)
       if ((png_byte)*ikp < 0x20 ||
          ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1))
       {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         char msg[40];
+         PNG_WARNING_PARAMETERS(p)
 
-         png_snprintf(msg, 40,
-             "invalid keyword character 0x%02X", (png_byte)*ikp);
-         png_warning(png_ptr, msg);
-#else
-         png_warning(png_ptr, "invalid character in keyword");
-#endif
+         png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x,
+            (png_byte)*ikp);
+         png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1");
          *dp = ' ';
       }
 
@@ -1499,6 +1728,7 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
    png_write_chunk_data(png_ptr, &buf, (png_size_t)1);
 
    /* Write the compressed data */
+   comp.input_len = text_len;
    png_write_compressed_data_out(png_ptr, &comp);
 
    /* Close the chunk */
@@ -1871,6 +2101,7 @@ png_write_start_row(png_structp png_ptr)
       png_ptr->usr_width = png_ptr->width;
    }
 
+   png_zlib_claim(png_ptr, PNG_ZLIB_FOR_IDAT);
    png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
    png_ptr->zstream.next_out = png_ptr->zbuf;
 }
@@ -1992,7 +2223,7 @@ png_write_finish_row(png_structp png_ptr)
           png_ptr->zstream.avail_out);
    }
 
-   deflateReset(&png_ptr->zstream);
+   png_zlib_release(png_ptr);
    png_ptr->zstream.data_type = Z_BINARY;
 }
 
@@ -2181,6 +2412,8 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
  * been specified by the application, and then writes the row out with the
  * chosen filter.
  */
+static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row);
+
 #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
 #define PNG_HISHIFT 10
 #define PNG_LOMASK ((png_uint_32)0xffffL)
@@ -2856,7 +3089,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
 
 
 /* Do the actual writing of a previously filtered row. */
-void /* PRIVATE */
+static void
 png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
 {
    png_size_t avail;
@@ -2916,8 +3149,6 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
       {
          /* Write the IDAT and reset the zlib output buffer */
          png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
-         png_ptr->zstream.next_out = png_ptr->zbuf;
-         png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
       }
    /* Repeat until all data has been compressed */
    } while (avail > 0 || png_ptr->zstream.avail_in > 0);
index 8f393fa38eb0274fba6a4c318703f19e45b69d13..beb5fb8cb40821e1180864c9573ca2104b57b21a 100644 (file)
@@ -1,9 +1,9 @@
 
-Makefiles for  libpng version 1.5.2 - March 31, 2011
+Makefiles for  libpng version 1.5.4 - July 7, 2011
 
 pnglibconf.h.prebuilt       =>  Stores configuration settings
  makefile.linux    =>  Linux/ELF makefile
-                       (gcc, creates libpng15.so.15.1.5.2)
+                       (gcc, creates libpng15.so.15.1.5.4)
  makefile.gcc      =>  Generic makefile (gcc, creates static libpng.a)
  makefile.knr      =>  Archaic UNIX Makefile that converts files with
                        ansi2knr (Requires ansi2knr.c from
@@ -20,7 +20,7 @@ pnglibconf.h.prebuilt       =>  Stores configuration settings
  makefile.dec      =>  DEC Alpha UNIX makefile
  makefile.dj2      =>  DJGPP 2 makefile
  makefile.elf      =>  Linux/ELF makefile symbol versioning,
-                       (gcc, creates libpng15.so.15.1.5.2)
+                       (gcc, creates libpng15.so.15.1.5.4)
  makefile.freebsd  =>  FreeBSD makefile
  makefile.gcc      =>  Generic gcc makefile
  makefile.hpgcc    =>  HPUX makefile using gcc
@@ -35,19 +35,18 @@ pnglibconf.h.prebuilt       =>  Stores configuration settings
  makefile.os2      =>  OS/2 Makefile (gcc and emx, requires libpng.def)
  makefile.sco      =>  For SCO OSr5  ELF and Unixware 7 with Native cc
  makefile.sggcc    =>  Silicon Graphics (gcc,
-                       creates libpng15.so.15.1.5.2)
+                       creates libpng15.so.15.1.5.4)
  makefile.sgi      =>  Silicon Graphics IRIX makefile (cc, creates static lib)
  makefile.solaris  =>  Solaris 2.X makefile (gcc,
-                       creates libpng15.so.15.1.5.2)
+                       creates libpng15.so.15.1.5.4)
  makefile.so9      =>  Solaris 9 makefile (gcc,
-                       creates libpng15.so.15.1.5.2)
+                       creates libpng15.so.15.1.5.4)
  makefile.std      =>  Generic UNIX makefile (cc, creates static libpng.a)
  makefile.sunos    =>  Sun makefile
  makefile.32sunu   =>  Sun Ultra 32-bit makefile
  makefile.64sunu   =>  Sun Ultra 64-bit makefile
  makefile.tc3      =>  Turbo C 3.0 makefile
  makefile.vcwin32  =>  makefile for Microsoft Visual C++ 4.0 and later
- makefile.watcom   =>  Watcom 10a+ Makefile, 32-bit flat memory model
  makevms.com       =>  VMS build script
  smakefile.ppc     =>  AMIGA smakefile for SAS C V6.58/7.00 PPC compiler
                        (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc)
@@ -58,7 +57,7 @@ Other supporting scripts:
  libpng-config-body.in => used by several makefiles to create libpng-config
  libpng-config-head.in => used by several makefiles to create libpng-config
  libpng.pc.in      =>  Used by several makefiles to create libpng.pc
- pngwin.rc         =>  Used by the visualc6 and visualc71 projects.
+ pngwin.rc         =>  Used by the visualc71 project.
  pngwin.def        =>  Used by makefile.os2
  pngwin.dfn        =>  Used to maintain pngwin.def
  SCOPTIONS.ppc     =>  Used with smakefile.ppc
index 6918d126e5786c0e8ae73dfb49bc2e96575eb113..a20e77e6abe1607473820d2fbe924527edd75aac 100755 (executable)
@@ -11,7 +11,7 @@
 
 # Modeled after libxml-config.
 
-version=1.5.2
+version=1.5.4
 prefix=""
 libdir=""
 libs=""
index 85beca6e0bcc0c85a7436bee8151b2ab8341049e..ba70c3f91f70e6fa983ac427292ad15850e41e83 100644 (file)
@@ -5,6 +5,6 @@ includedir=@includedir@/libpng15
 
 Name: libpng
 Description: Loads and saves PNG files
-Version: 1.5.2
+Version: 1.5.4
 Libs: -L${libdir} -lpng15
 Cflags: -I${includedir}
index 28fb3ac6ad81c120c501a8a0a807b4d2be30f683..57414dd4b881aa20c07ee83ed709caf5b6a5cda2 100644 (file)
@@ -23,7 +23,7 @@
 
 VERMAJ = 1
 VERMIN = 5
-VERMIC = 2
+VERMIC = 4
 VER = $(VERMAJ).$(VERMIN).$(VERMIC)
 NAME = libpng
 PACKAGE = $(NAME)-$(VER)
index 59296562b660c48ca57762ae6466ca784217e09b..f91d464442073dbab4155a951eab9771e66a215e 100644 (file)
@@ -10,7 +10,7 @@
 # Library name:
 LIBNAME = libpng15
 PNGMAJ = 15
-RELEASE = 2
+RELEASE = 4
 
 # Shared library names:
 LIBSO=$(LIBNAME).so
index 1db9cf9511c369207349b6c59d7c35d1cd5ba0c8..d69781cca0e14df6b6f47035cac940bc1c2eb10e 100644 (file)
@@ -17,7 +17,7 @@ INCSDIR=${LOCALBASE}/include/libpng15
 
 LIB=   png15
 SHLIB_MAJOR=   0
-SHLIB_MINOR=   1.5.2
+SHLIB_MINOR=   1.5.4
 SRCS=  png.c pngset.c pngget.c pngrutil.c pngtrans.c pngwutil.c \
        pngread.c pngrio.c pngwio.c pngwrite.c pngrtran.c \
        pngwtran.c pngmem.c pngerror.c pngpread.c
index 8a1fa967eab82fe2d8a70d0772e7d43cd4a99d27..ad713c96e72ff2bff369bf7bbf814cff0e41dcab 100644 (file)
@@ -17,7 +17,7 @@ INCSDIR=${LOCALBASE}/include
 
 LIB=   png
 SHLIB_MAJOR=   15
-SHLIB_MINOR=   1.5.2
+SHLIB_MINOR=   1.5.4
 SRCS=  png.c pngset.c pngget.c pngrutil.c pngtrans.c pngwutil.c \
        pngread.c pngrio.c pngwio.c pngwrite.c pngrtran.c \
        pngwtran.c pngmem.c pngerror.c pngpread.c
index 4ec9d2f5a6ce43d62b2fa08a454fd4e6f9bcaff7..5fd72518d37453a6c46d04b2e865e7a4b54bc3af 100644 (file)
@@ -11,7 +11,7 @@ LIBDIR=       ${PREFIX}/lib
 MANDIR= ${PREFIX}/man/cat
 
 SHLIB_MAJOR=   15
-SHLIB_MINOR=   1.5.2
+SHLIB_MINOR=   1.5.4
 
 LIB=   png
 SRCS=  png.c pngerror.c pngget.c pngmem.c pngpread.c \
index 96c600eab091f93c31d698b6969cc86619fa30d0..24f07137f189a6c26c9089a75af712fd26da2461 100755 (executable)
@@ -48,7 +48,7 @@ BEGIN{
    deb=0                        # debug - set on command line
    everything=""                # do not override defaults
    logunsupported=0             # write unsupported options too
-   
+
    # Precreate arrays
    option[""] = ""    # list of all options: default enabled/disabled
    done[""] = 1       # marks option as having been output
@@ -301,7 +301,7 @@ pre != 0 && $1 == "chunk" && NF >= 2{
 #   macro is not defined.  The default value will be re-tokenised.
 #   (BTW: this is somewhat restrictive, it mainly exists for the
 #   support of non-standard configurations and numeric parameters,
-#   see the uses in scripts/options.dat 
+#   see the uses in scripts/options.dat
 
 $1 == "setting" && (NF == 2 || NF >= 3 && ($3 == "requires" || $3 == "default")){
    reqs = ""
index 26afef866eb7f2abde9354eb7602fd00679f46b3..dfa79651eec361b30666f6d29d3c75d9d0c055d3 100644 (file)
@@ -6,7 +6,7 @@
 #
 com pnglibconf.h - library build configuration
 com
-com libpng version 1.5.0 - January 6, 2011
+com libpng version 1.5.3 -  July 7, 2011
 com
 com Copyright (c) 1998-2011 Glenn Randers-Pehrson
 com
@@ -43,7 +43,7 @@ file pnglibconf.h scripts/pnglibconf.dfa PNGLCONF_H
 
 # The following setting, option and chunk values can all be changed
 # while building libpng:
-# 
+#
 # setting: change 'setting' lines to fine tune library performance,
 #   changes to the settings don't affect the libpng API functionally
 #
@@ -62,7 +62,7 @@ file pnglibconf.h scripts/pnglibconf.dfa PNGLCONF_H
 # don't want in that file in that file.  You can also turn on options
 # using PNG_<option>_SUPPORTED.  When you have finished rerun
 # configure and rebuild pnglibconf.h file with -DPNG_USER_CONFIG:
-# 
+#
 #  make clean
 #  CPPFLAGS='-DPNG_USER_CONFIG' ./configure
 #  make pnglibconf.h
@@ -73,7 +73,7 @@ file pnglibconf.h scripts/pnglibconf.dfa PNGLCONF_H
 #
 # 2) Add definitions of the settings you want to change to
 # CPPFLAGS; for example:
-# 
+#
 #   -DPNG_DEFAULT_READ_MACROS=0
 #
 # (This would change the default to *not* use read macros.)  Be
@@ -193,11 +193,11 @@ option FLOATING_ARITHMETIC
 option FLOATING_POINT enables ok_math
 option FIXED_POINT enables ok_math
 
-# Added at libpng version 1.4.0 
+# Added at libpng version 1.4.0
 
 option ERROR_TEXT
 
-# The following is always on (defined empty) 
+# The following is always on (defined empty)
 
 setting CALLOC_SUPPORTED default
 
@@ -214,9 +214,9 @@ option STDIO
 option CONSOLE_IO requires STDIO
 
 # Note: prior to 1.5.0 this option could not be disabled if STDIO
-# was enabled.
+# was enabled.  Prior to 1.5.3 this option required STDIO
 
-option TIME_RFC1123 requires STDIO
+option TIME_RFC1123
 
 # PNG_SETJMP_NOT_SUPPORTED is an old equivalent for NO_SETJMP
 
@@ -293,8 +293,10 @@ option READ enables READ_INTERLACING
 
 # Disabling READ_16BIT does not disable reading 16-bit PNG files, but it
 # forces them to be chopped down to 8-bit, and disables any 16-bit
-# processing after that has happened.  You need to be sure to enable READ_16_TO_8
-# when you disable READ_16BIT for this to work properly.
+# processing after that has happened.  You need to be sure to enable
+# READ_SCALE_16_TO_8 or READ_STRIP_16_TO_8 when you disable READ_16BIT for
+# this to work properly.  You should disable the other option if you need to
+# ensure a particular convertion (otherwise the app can chose.)
 
 option READ_16BIT requires READ enables 16BIT
 
@@ -311,11 +313,14 @@ option READ_BGR requires READ_TRANSFORMS
 option READ_SWAP requires READ_TRANSFORMS READ_16BIT
 option READ_PACKSWAP requires READ_TRANSFORMS
 option READ_INVERT requires READ_TRANSFORMS
-option READ_BACKGROUND requires READ_TRANSFORMS
-option READ_16_TO_8 requires READ_TRANSFORMS
+option READ_BACKGROUND requires READ_TRANSFORMS enables READ_STRIP_ALPHA
+option READ_STRIP_16_TO_8 requires READ_TRANSFORMS
+option READ_SCALE_16_TO_8 requires READ_TRANSFORMS
 option READ_FILLER requires READ_TRANSFORMS
 option READ_GAMMA requires READ_TRANSFORMS enables READ_gAMA
 option READ_GRAY_TO_RGB requires READ_TRANSFORMS
+
+option READ_ALPHA_MODE requires READ_TRANSFORMS enables READ_GAMMA
 option READ_SWAP_ALPHA requires READ_TRANSFORMS
 option READ_INVERT_ALPHA requires READ_TRANSFORMS
 option READ_STRIP_ALPHA requires READ_TRANSFORMS
@@ -340,12 +345,14 @@ option READ_COMPOSITE_NODIV requires READ
 option INCH_CONVERSIONS
 = INCH_CONVERSIONS INCH_CONVERSIONS
 
-# IN DEVELOPMENT
-# These are currently experimental features, define them if you want
+# API to build a grayscale palette
+
+option BUILD_GRAYSCALE_PALETTE
 
-# Very little testing, not enabled by default.
+# IN DEVELOPMENT
+# These are currently experimental features; define them if you want
 
-option READ_16_TO_8_ACCURATE_SCALE requires READ disabled
+# NOTHING HERE
 
 # WRITE options
 
@@ -386,6 +393,11 @@ option WRITE_FLUSH requires WRITE
 option USER_TRANSFORM_PTR if READ_USER_TRANSFORM WRITE_USER_TRANSFORM
 option USER_TRANSFORM_INFO if READ_USER_TRANSFORM WRITE_USER_TRANSFORM
 
+# This enables API to set compression parameters for compressing
+# non-IDAT chunks (zTXt, iTXt, iCCP, and unknown chunks).  This feature
+# was added at libpng-1.5.3.
+option WRITE_CUSTOMIZE_ZTXT_COMPRESSION requires WRITE
+
 # Any chunks you are not interested in, you can undef here.  The
 # ones that allocate memory may be expecially important (hIST,
 # tEXt, zTXt, tRNS, pCAL).  Others will just save time and make png_info
@@ -501,7 +513,7 @@ chunk cHRM
 chunk gAMA
 chunk hIST
 chunk iCCP
-chunk iTXt requires TEXT
+chunk iTXt
 chunk oFFs
 chunk pCAL
 chunk sCAL
@@ -512,7 +524,7 @@ chunk sRGB
 chunk tEXt requires TEXT
 chunk tIME
 chunk tRNS
-chunk zTXt requires TEXT
+chunk zTXt
 
 # This only affects support of the optional PLTE chunk in RGB and RGBA
 # images.  Notice that READ_ANCILLARY_CHUNKS therefore disables part
@@ -541,9 +553,25 @@ option SAVE_INT_32 requires WRITE
 
 # png_save_int_32 is required by the ancillary chunks oFFs and pCAL
 
+# added at libpng-1.5.4
+
+option WRITE_OPTIMIZE_CMF requires WRITE
+
+option READ_COMPRESSED_TEXT disabled
+option READ_iCCP enables READ_COMPRESSED_TEXT
+option READ_iTXt enables READ_COMPRESSED_TEXT
+option READ_zTXt enables READ_COMPRESSED_TEXT
+option READ_COMPRESSED_TEXT enables READ_TEXT
+
 option WRITE_oFFs enables SAVE_INT_32
 option WRITE_pCAL enables SAVE_INT_32
 
+option WRITE_COMPRESSED_TEXT disabled
+option WRITE_iCCP enables WRITE_COMPRESSED_TEXT
+option WRITE_iTXt enables WRITE_COMPRESSED_TEXT
+option WRITE_zTXt enables WRITE_COMPRESSED_TEXT
+option WRITE_COMPRESSED_TEXT enables WRITE_TEXT
+
 # Turn this off to disable png_read_png() and png_write_png() and
 # leave the row_pointers member out of the info structure.
 
index 5f0c8525bea233036d6396be6ae8084e58d36326..827d17e544c8d68952319b62e7ff05937bcbdb46 100644 (file)
@@ -3,7 +3,7 @@
 
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.5.0 - last changed on February 11, 2011 */
+/* libpng version 1.5.4 - last changed on June 22, 2011 */
 
 /* Copyright (c) 1998-2011 Glenn Randers-Pehrson */
 
@@ -17,7 +17,7 @@
 /* pnglibconf.dfa with respect to the dependencies between the following */
 /* symbols.  It is much better to generate a new file using */
 /* scripts/libpngconf.mak */
-  
+
 #ifndef PNGLCONF_H
 #define PNGLCONF_H
 /* settings */
 #define PNG_ALIGN_MEMORY_SUPPORTED
 #define PNG_BENIGN_ERRORS_SUPPORTED
 #define PNG_bKGD_SUPPORTED
+#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
 #define PNG_CHECK_cHRM_SUPPORTED
 #define PNG_cHRM_SUPPORTED
 #define PNG_CONSOLE_IO_SUPPORTED
 #define PNG_CONVERT_tIME_SUPPORTED
 #define PNG_EASY_ACCESS_SUPPORTED
+/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
 #define PNG_ERROR_TEXT_SUPPORTED
 #define PNG_FIXED_POINT_SUPPORTED
 #define PNG_FLOATING_ARITHMETIC_SUPPORTED
 #define PNG_POINTER_INDEXING_SUPPORTED
 #define PNG_PROGRESSIVE_READ_SUPPORTED
 #define PNG_READ_16BIT_SUPPORTED
-#define PNG_READ_16_TO_8_SUPPORTED
+#define PNG_READ_ALPHA_MODE_SUPPORTED
 #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
 #define PNG_READ_BACKGROUND_SUPPORTED
 #define PNG_READ_BGR_SUPPORTED
 #define PNG_READ_bKGD_SUPPORTED
 #define PNG_READ_cHRM_SUPPORTED
 #define PNG_READ_COMPOSITE_NODIV_SUPPORTED
+#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
 #define PNG_READ_EXPAND_16_SUPPORTED
 #define PNG_READ_EXPAND_SUPPORTED
 #define PNG_READ_FILLER_SUPPORTED
 #define PNG_READ_QUANTIZE_SUPPORTED
 #define PNG_READ_RGB_TO_GRAY_SUPPORTED
 #define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_SCALE_16_TO_8_SUPPORTED
 #define PNG_READ_sCAL_SUPPORTED
 #define PNG_READ_SHIFT_SUPPORTED
 #define PNG_READ_sPLT_SUPPORTED
 #define PNG_READ_sRGB_SUPPORTED
+#define PNG_READ_STRIP_16_TO_8_SUPPORTED
 #define PNG_READ_STRIP_ALPHA_SUPPORTED
 #define PNG_READ_SUPPORTED
 #define PNG_READ_SWAP_ALPHA_SUPPORTED
 #define PNG_WRITE_BGR_SUPPORTED
 #define PNG_WRITE_bKGD_SUPPORTED
 #define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
 #define PNG_WRITE_FILLER_SUPPORTED
 #define PNG_WRITE_FILTER_SUPPORTED
 #define PNG_WRITE_FLUSH_SUPPORTED
 #define PNG_WRITE_INVERT_SUPPORTED
 #define PNG_WRITE_iTXt_SUPPORTED
 #define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
 #define PNG_WRITE_PACK_SUPPORTED
 #define PNG_WRITE_PACKSWAP_SUPPORTED
 #define PNG_WRITE_pCAL_SUPPORTED
 #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
 #define PNG_WRITE_zTXt_SUPPORTED
 #define PNG_zTXt_SUPPORTED
-/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
-/*#undef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED*/
 /* end of options */
 #endif /* PNGLCONF_H */
index f8719185da29ff0bdede0b31f68eeadd2b67a33c..1509ee242ec82434734d9b88d4eccc76fc408124 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/make -f
 # pnglibconf.mak - standard make lines for pnglibconf.h
-# 
+#
 # These lines are copied from Makefile.am, they illustrate
 # how to automate the build of pnglibconf.h from scripts/pnglibconf.dfa
 # given 'awk' and 'sed'
index 46f96132479f498b543e7cd1cac805e69dcf1269..487f2b4349133ecd80e892a1c21593328e24c0a4 100644 (file)
@@ -5,7 +5,7 @@
 LIBRARY
 
 EXPORTS
-;Version 1.5.2
+;Version 1.5.4
  png_access_version_number @1
  png_set_sig_bytes @2
  png_sig_cmp @3
@@ -227,3 +227,11 @@ EXPORTS
  png_process_data_pause @219
  png_process_data_skip @220
  png_set_expand_16 @221
+ png_set_text_compression_level @222
+ png_set_text_compression_mem_level @223
+ png_set_text_compression_strategy @224
+ png_set_text_compression_window_bits @225
+ png_set_text_compression_method @226
+ png_set_alpha_mode @227
+ png_set_alpha_mode_fixed @228
+ png_set_scale_16 @229
index 1ab06f5d1114290809ddb6384f14c83cdd3510b2..d8c6faa23b468cb24bfc78d01fb649b780f68773 100755 (executable)
@@ -7,9 +7,9 @@ echo >> pngtest-log.txt
 echo "============ pngvalid-full.sh ==============" >> pngtest-log.txt
 
 echo "Running test-pngvalid-full.sh"
-for gamma in threshold transform sbit 16-to-8
+for gamma in threshold transform sbit 16-to-8 background alpha-mode "transform --expand16" "background --expand16" "alpha-mode --expand16"
 do
-   if ./pngvalid "--gamma-$gamma" >> pngtest-log.txt 2>&1
+   if ./pngvalid --gamma-$gamma >> pngtest-log.txt 2>&1
    then
       echo "  PASS:" pngvalid "--gamma-$gamma"
    else
index ae2907df1a6799fb553ef7d55133ac9ca174b982..7a68a4ca9f45504ecb1d1cf8496e7369a5a65759 100644 (file)
@@ -28,7 +28,7 @@
  *                  -#L4SIGMA0_IPCERROR IPC error
  *                  -#L4SIGMA0_NOFPAGE  no fpage received
  */
-int
+L4_CV int
 l4sigma0_map_anypage(l4_cap_idx_t pager, l4_addr_t map_area,
                     unsigned log2_map_size, l4_addr_t *base, unsigned sz)
 {
index 5c5cdda5f10f074fddc5fd8643e3a8338e3872ab..651d26f312f99c2a0b89efe1b30590a7e8b4bf87 100644 (file)
@@ -18,7 +18,8 @@
  *                  -#L4SIGMA0_IPCERROR IPC error
  *                  -#L4SIGMA0_NOFPAGE  no fpage received
  */
-int l4sigma0_new_client(l4_cap_idx_t pager, l4_cap_idx_t gate)
+L4_CV int
+l4sigma0_new_client(l4_cap_idx_t pager, l4_cap_idx_t gate)
 {
   l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 1, 0, 0);
   l4_utcb_t *utcb = l4_utcb();
index 40321d8eadddce9182004334cb02139197c54111..ccb66be66762aa3531d5e1f88ecac8d4cbed225e 100644 (file)
@@ -10,7 +10,7 @@
 #include <l4/sys/ipc.h>
 #include <l4/sigma0/sigma0.h>
 
-void
+L4_CV void
 l4sigma0_debug_dump(l4_cap_idx_t pager)
 {
   l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 1, 0, 0);
index 967a080b217a59d24bf88e4da3e8a9cf86eb53ac..f28e2906d0e6be9c90a95aa63248e3e2c47adf88 100644 (file)
@@ -30,7 +30,7 @@
  *          -#L4SIGMA0_IPCERROR   IPC error
  *          -#L4SIGMA0_NOFPAGE    no fpage received
  */
-int
+L4_CV int
 l4sigma0_map_iomem(l4_cap_idx_t pager,
                    l4_addr_t phys, l4_addr_t virt, l4_addr_t size, int cached)
 {
index e0ef7575e0b68eebe7a140183d97247a41938b06..27bd755a5ed08a429f4502014d5713d2a85eed47 100644 (file)
@@ -4,7 +4,7 @@
  *
  * \date       02/2006
  * \author     Adam Lackorzynski <adam@os.inf.tu-dresden.de>
- *             Frank Mehnert <fm3@os.inf.tu-dresden.de> */
+ *             Frank Mehnert <fm3@os.inf.tu-dresden.de> */
 
 /*
  * (c) 2006-2009 Author(s)
@@ -20,7 +20,7 @@
 /*
  * \return kip address, 0 on error
  */
-l4_kernel_info_t *
+L4_CV l4_kernel_info_t *
 l4sigma0_map_kip(l4_cap_idx_t pager, void *adr, unsigned log2_size)
 {
   l4_msgtag_t tag = l4_msgtag(L4_PROTO_SIGMA0, 1, 0, 0);
index ad7660b755863eeb21718ef83f8ac6bfd4b595e6..babd899932575f985b45758bdde7bcbbf96d848e 100644 (file)
@@ -25,7 +25,7 @@
  *          -#L4SIGMA0_IPCERROR   IPC error
  *          -#L4SIGMA0_NOFPAGE    no fpage received
  */
-int
+L4_CV int
 l4sigma0_map_mem(l4_cap_idx_t pager,
                 l4_addr_t phys, l4_addr_t virt, l4_addr_t size)
 {
index 82f23a168d231b3102f664f5c33c69c2bf7159d8..e60078a1b10209024ba68a3f6d350fdc171c7eef 100644 (file)
@@ -25,7 +25,7 @@
  *         -#L4SIGMA0_IPCERROR IPC error
  *         -#L4SIGMA0_NOFPAGE  no fpage received
  */
-int
+L4_CV int
 l4sigma0_map_tbuf(l4_cap_idx_t pager, l4_addr_t virt)
 {
   //assert(0);
index e1e0ec3e1f3d0a5727e09f44601682368bdb605d..f943bca03f403d191d18aed20dd1e1db5254259e 100644 (file)
@@ -35,6 +35,11 @@ ifeq ("$(GCCMAJORVERSION)", "4")
     STDCXX_CONTRIB_VERSION_4.6_PLUS := y
     STDCXX_0x = y
   endif
+  ifeq ("$(GCCMINORVERSION)", "7")
+    STDCXX_CONTRIB_VERSION := 4.6
+    STDCXX_CONTRIB_VERSION_4.6_PLUS := y
+    STDCXX_0x = y
+  endif
   ifneq ("$(call gte, $(__GCCMINOR), $(call n, 1))", "")
     STDCXX_CONTRIB_VERSION ?= 4.1.0
   endif
index db715366e9a017beb2fd2f2306c2dc9f280db5b2..a70a331c8e72ccf11cebcae30aa3312812a60555 100644 (file)
@@ -16,7 +16,7 @@
 
 inline void
 l4vbus_device_msg(l4vbus_device_handle_t handle, l4_uint32_t op,
-                  L4::Ipc_iostream &s)
+                  L4::Ipc::Iostream &s)
 {
   s << handle << op;
 }
index 4aaf3f1990778c4e6fff281afad256fd8d038334..5bc4923fbc6ccb4a7ec8424b2386509ffbfc73b7 100644 (file)
@@ -19,7 +19,7 @@ l4vbus_get_device_by_hid(l4_cap_idx_t vbus, l4vbus_device_handle_t parent,
                          l4vbus_device_handle_t *child, char const *hid,
                          int depth, l4vbus_device_t *devinfo)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << parent << l4_uint32_t(L4vbus_vdevice_get_by_hid) << *child << depth
     << hid;
   int err = l4_error(s.call(vbus));
@@ -42,7 +42,7 @@ l4vbus_get_next_device(l4_cap_idx_t vbus, l4vbus_device_handle_t parent,
                        l4vbus_device_handle_t *child, int depth,
                        l4vbus_device_t *devinfo)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << parent << l4_uint32_t(L4vbus_vdevice_get_next) << *child << depth;
   int err = l4_error(s.call(vbus));
   if (err < 0)
@@ -60,7 +60,7 @@ int
 l4vbus_get_resource(l4_cap_idx_t vbus, l4vbus_device_handle_t dev,
                     int res_idx, l4vbus_resource_t *res)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << dev << l4_uint32_t(L4vbus_vdevice_get_resource) << res_idx;
   int err = l4_error(s.call(vbus));
   if (err < 0)
@@ -82,11 +82,11 @@ __vbus_request_port(l4_cap_idx_t vbus, l4vbus_resource_t const &res)
       l4_uint16_t log2_size = l4util_splitlog2_size(r.start, res.end);
       r.end = r.start + (1UL << log2_size) -1;
 
-      L4::Ipc_iostream s(l4_utcb());
+      L4::Ipc::Iostream s(l4_utcb());
       s << l4vbus_device_handle_t(0)
         << L4::Opcode(L4vbus_vbus_request_resource);
       s.put(r);
-      s << L4::Rcv_fpage::io(r.start, log2_size, 0);
+      s << L4::Ipc::Rcv_fpage::io(r.start, log2_size, 0);
 
       long err= l4_error(s.call(vbus));
       if (err < 0)
@@ -109,7 +109,7 @@ l4vbus_request_resource(l4_cap_idx_t vbus, l4vbus_resource_t *res,
 int
 l4vbus_release_resource(l4_cap_idx_t vbus, l4vbus_resource_t *res)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << l4vbus_device_handle_t(0)
     << l4_uint32_t(L4vbus_vbus_release_resource) << res->type << res->start
     << res->end;
@@ -122,9 +122,9 @@ int
 l4vbus_vicu_get_cap(l4_cap_idx_t vbus, l4vbus_device_handle_t icu,
                     l4_cap_idx_t res)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   s << icu << l4_uint32_t(L4vbus_vicu_get_cap);
-  s << L4::Small_buf(res);
+  s << L4::Ipc::Small_buf(res);
   int err = l4_error(s.call(vbus));
 
   return err;
index 393fd4796166411b47eb300090b12d466e1487d2..a2f38c3574ebb8df1e6f65c896bfc8850c52af51 100644 (file)
@@ -15,7 +15,7 @@ int L4_CV
 l4vbus_gpio_write(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                   int pin, int val)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_gpio_write, s);
   s << pin << val;
   int err = l4_error(s.call(vbus));
@@ -26,7 +26,7 @@ int L4_CV
 l4vbus_gpio_read(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                  int  pin, int *val)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_gpio_read, s);
   s << pin;
   int err = l4_error(s.call(vbus));
index 0d02564f73571d018a1da3bb32127f6a25ca29ba..5789228976bfd4ed53105a81f6831be120fbc40f 100644 (file)
@@ -16,10 +16,10 @@ l4vbus_i2c_write(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                  l4_uint16_t addr, l4_uint8_t sub_addr,
                  l4_uint8_t *buffer, unsigned long size)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_i2c_write, s);
   s << addr << sub_addr << size;
-  s << L4::ipc_buf_cp_out(buffer, size);
+  s << L4::Ipc::Buf_cp_out<l4_uint8_t>(buffer, size);
   return l4_error(s.call(vbus));
 }
 
@@ -28,13 +28,13 @@ l4vbus_i2c_read(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                 l4_uint16_t addr, l4_uint8_t sub_addr,
                 l4_uint8_t *buffer, unsigned long *size)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_i2c_read, s);
   s << addr << sub_addr << *size;
 
   int err = l4_error(s.call(vbus));
   if (err)
     return err;
-  s >> *size >> L4::ipc_buf_cp_in(buffer, *size);
+  s >> *size >> L4::Ipc::Buf_cp_in<l4_uint8_t>(buffer, *size);
   return 0;
 }
index 133bcb8672270eedbf2cd58792a52a5d72c58c45..407ac6eaf20f7ebee044b0195b401a3e36840327 100644 (file)
@@ -15,7 +15,7 @@ int L4_CV
 l4vbus_mcspi_read(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                   unsigned channel, l4_umword_t *value)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_mcspi_read, s);
   s << channel;
   int ret = l4_error(s.call(vbus));
@@ -28,7 +28,7 @@ int L4_CV
 l4vbus_mcspi_write(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                    unsigned channel, l4_umword_t value)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, L4vbus_mcspi_write, s);
   s << channel << value;
   return l4_error(s.call(vbus));
index c7260eb9ba052b461274500e83b56cfae88b4876..74e9ca2984724c87be6633b85d4696759d09acc3 100644 (file)
@@ -16,7 +16,7 @@ l4vbus_pci_cfg_read(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                     l4_uint32_t bus, l4_uint32_t devfn,
                     l4_uint32_t reg, l4_uint32_t *value, l4_uint32_t width)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, 0, s);
   s << bus << devfn << reg << width;
   int err = l4_error(s.call(vbus));
@@ -31,7 +31,7 @@ l4vbus_pci_cfg_write(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                      l4_uint32_t bus, l4_uint32_t devfn,
                      l4_uint32_t reg, l4_uint32_t value, l4_uint32_t width)
 {
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, 1, s);
   s << bus << devfn << reg << value << width;
   return l4_error(s.call(vbus));
@@ -43,7 +43,7 @@ l4vbus_pci_irq_enable(l4_cap_idx_t vbus, l4vbus_device_handle_t handle,
                       int pin, unsigned char *trigger, unsigned char *polarity)
 {
   int irq;
-  L4::Ipc_iostream s(l4_utcb());
+  L4::Ipc::Iostream s(l4_utcb());
   l4vbus_device_msg(handle, 2, s);
   s << bus << devfn << pin;
   int err = l4_error(s.call(vbus));
index 4ba4efd7021d1f2bee62094a5920ab91889fafcf..20fd02cb64325ebfa86a9edb5f27a7fa00f68f8e 100644 (file)
@@ -234,7 +234,7 @@ public:
    *
    * \return 0 for success, error code otherwise
    */
-  static int
+  L4_CV static int
   ext_alloc(Vcpu **vcpu,
             l4_addr_t *ext_state,
             L4::Cap<L4::Task> task = L4Re::Env::env()->task(),
index b2968aaea366605d1f786563bbbbf023a59e6e4c..c19a2ee40396fb4d41ae19b0ebc48e1e23f9b9f4 100644 (file)
@@ -9,6 +9,6 @@ SRC_CC          = main.cc slab_alloc.cc \
 LDFLAGS +=
 #CPPFLAGS += -fPIC
 
-REQUIRES_LIBS  := libloader libkproxy
+REQUIRES_LIBS  := libloader libkproxy cxx_libc_io cxx_io
 
 include $(L4DIR)/mk/prog.mk
index 9d4a2cc351f0573500d29d92e60c697a3c92fddd..ff7fdb079c220ad5ac1762eb1590f85ee87324c7 100644 (file)
@@ -52,7 +52,7 @@ public:
 };
 
 int
-Allocator::disp_factory(l4_umword_t, L4::Ipc_iostream &ios)
+Allocator::disp_factory(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Factory::Proto o;
   ios >> o;
@@ -132,7 +132,7 @@ Allocator::disp_factory(l4_umword_t, L4::Ipc_iostream &ios)
 }
 
 int
-Allocator::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Allocator::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index b3fc053508d658a2d3d7c3b539df39c1ed4d5e91..1bca49c1563381d81096e2a23d11a2f044f0ad58 100644 (file)
@@ -24,8 +24,8 @@ public:
 
   virtual ~Allocator();
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
-  int disp_factory(l4_umword_t, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
+  int disp_factory(l4_umword_t, L4::Ipc::Iostream &ios);
 
   static Allocator *root_allocator();
 };
index 21f0baddf6a4b5ec485ed8bf3d015e4b3650d682..6258fd53f6127bb9717e5615439998800ac6555a 100644 (file)
@@ -40,7 +40,7 @@ void App_task::operator delete (void *m) throw()
 #endif
 
 int
-App_task::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+App_task::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index 99872359f32a476806a8fda1e031e2f345c39a11..09b7861896cd8396ef64d44fd7bd6d6a69c2c66d 100644 (file)
@@ -30,7 +30,7 @@ public:
   App_task();
   static L4::Cap<L4Re::Mem_alloc> allocator()
   { return L4Re::Env::env()->mem_alloc(); }
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 
   Region_map *rm() { return &_rm; }
index cf8c2104ffaf7819fbc5f7adc0fa3fa01a3d443b..62d964eab20835a54d602c4893fe441aea5e5a73 100644 (file)
@@ -39,7 +39,7 @@ static void mycpy(char **buf, int *rem, char const *s, int l)
 static char msgbuf[4096];
 
 int
-Ldr::Log::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Ldr::Log::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -59,7 +59,7 @@ Ldr::Log::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
   char *msg = Glbl::log_buffer;
   unsigned long len_msg = sizeof(Glbl::log_buffer);
 
-  ios >> L4::ipc_buf_cp_in(msg, len_msg);
+  ios >> L4::Ipc::Buf_cp_in<char>(msg, len_msg);
 
   int rem = sizeof(msgbuf);
   while (len_msg > 0 && msg[0])
index 083b58f1f8d2443fb50b9cf289d51edceba7546d..a1266ea1e5c3487afca6c1e07886de9d1e384fdb 100644 (file)
@@ -40,7 +40,7 @@ public:
   char const *tag() const { return _tag; }
   unsigned char color() const { return _color; }
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   static int color_value(cxx::String const &col);
   virtual ~Log() {}
index 98dcddc3fdc5273cfe6719b3cceb863b3d1b6fe8..56d6f05a68badb87f89ea7a3e4e33f86574a43cb 100644 (file)
@@ -41,11 +41,11 @@ class Loop_hooks :
   public L4::Ipc_svr::Compound_reply
 {
 public:
-  static void setup_wait(L4::Ipc_istream &istr, bool before_reply)
+  static void setup_wait(L4::Ipc::Istream &istr, bool before_reply)
   {
     (void)before_reply;
     istr.reset();
-    istr << L4::Small_buf(Glbl::rcv_cap.cap(),  L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(Glbl::rcv_cap.cap(),  L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br()->bdr = 0;
   }
 };
index c41046e19efd557d6a620eb4f18333b645fb5661..06f22297e32996ddf8b63b5979c53ef583ca4cdc 100644 (file)
@@ -68,7 +68,7 @@ Name_space::free_dynamic_entry(Names::Entry *n)
 }
 
 int
-Name_space::get_capability(L4::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
+Name_space::get_capability(L4::Ipc::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
                            L4::Server_object **so)
 {
   if (cap_fp.id_received())
index 9fb9c2929f334e5721a1a50c22818a53b7adfc0f..d85f8f5b705aad07b9c89bcf10c25bfbaa49d512 100644 (file)
@@ -27,7 +27,7 @@ class Name_space : public L4::Server_object,
 {
 public:
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
   {
     enum { Max_name = 2048 };
     static char buffer[Max_name];
@@ -39,7 +39,7 @@ public:
   ~Name_space();
 
   // server support ----------------------------------------
-  int get_capability(L4::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
+  int get_capability(L4::Ipc::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
                      L4::Server_object **);
   int save_capability(L4::Cap<void> *cap);
   void free_capability(L4::Cap<void> cap);
index defccc5719b74eb8bce9e706ec632f76d728c1f5..b2e99f14a5f7baa44ea77a55ec2c730fa1538b82 100644 (file)
@@ -85,7 +85,7 @@ void Region_map::global_init()
 
 int
 Region_ops::map(Region_handler const *h, l4_addr_t local_adr,
-                Region const &r, bool writable, L4::Snd_fpage *result)
+                Region const &r, bool writable, L4::Ipc::Snd_fpage *result)
 {
   if ((h->flags() & Rm::Reserved) || !h->memory().is_valid())
     return -L4_ENOENT;
@@ -102,8 +102,8 @@ Region_ops::map(Region_handler const *h, l4_addr_t local_adr,
   if (int err = ds->map(offset, writable, map_area, map_area, map_end))
     return err;
 
-  *result = L4::Snd_fpage::mem(map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
-                               local_adr, L4::Snd_fpage::Grant);
+  *result = L4::Ipc::Snd_fpage::mem(map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
+                               local_adr, L4::Ipc::Snd_fpage::Grant);
   return L4_EOK;
 }
 
@@ -124,7 +124,7 @@ Region_ops::release(Region_handler const * /*h*/)
 
 template<typename T>
 inline
-T extract(L4::Ipc_istream &s)
+T extract(L4::Ipc::Istream &s)
 { T t; s >> t; return t; }
 
 void
@@ -166,7 +166,7 @@ class Rm_server
 public:
   typedef L4::Cap<L4Re::Dataspace> Dataspace;
   enum { Have_find = true };
-  static int validate_ds(L4::Snd_fpage const & /*ds_cap*/, unsigned, L4::Cap<L4Re::Dataspace> *ds)
+  static int validate_ds(L4::Ipc::Snd_fpage const & /*ds_cap*/, unsigned, L4::Cap<L4Re::Dataspace> *ds)
   {
     // XXX: must check that ds is from trusted allocator!
     *ds = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
@@ -182,13 +182,13 @@ public:
 };
 
 int
-Region_map::handle_rm_request(L4::Ipc_iostream &ios)
+Region_map::handle_rm_request(L4::Ipc::Iostream &ios)
 {
   return L4Re::Util::region_map_server<Rm_server>(this, ios);
 }
 
 int
-Region_map::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Region_map::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index 878402b7538f1494583f4bef5477bb64344bf3bd..4dd577e367a9305b62a5d4593397cac06e2a81b8 100644 (file)
@@ -26,10 +26,10 @@ typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>, Region_ops> Region_
 class Region_ops
 {
 public:
-  typedef L4::Snd_fpage Map_result;
+  typedef L4::Ipc::Snd_fpage Map_result;
   static int map(Region_handler const *h, l4_addr_t addr,
                  L4Re::Util::Region const &r, bool writable,
-                 L4::Snd_fpage *result);
+                 L4::Ipc::Snd_fpage *result);
 
   static void unmap(Region_handler const *h, l4_addr_t vaddr,
                     l4_addr_t offs, unsigned long size);
@@ -52,17 +52,17 @@ public:
   static void global_init();
 
   Region_map();
-  //void setup_wait(L4::Ipc_istream &istr);
-  int handle_pagefault(L4::Ipc_iostream &ios);
-  int handle_rm_request(L4::Ipc_iostream &ios);
+  //void setup_wait(L4::Ipc::Istream &istr);
+  int handle_pagefault(L4::Ipc::Iostream &ios);
+  int handle_rm_request(L4::Ipc::Iostream &ios);
   virtual ~Region_map() {}
 
   void init();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   void debug_dump(unsigned long function) const;
 private:
-  int reply_err(L4::Ipc_iostream &ios);
+  int reply_err(L4::Ipc::Iostream &ios);
 };
 
 
index c2fb41c06099f3e41ecc57398212d6cda716344f..986dd4f68b9e794db89e0215013331b2032ac8c1 100644 (file)
@@ -141,7 +141,7 @@ Sched_proxy::idle_time(l4_sched_cpu_set_t const &)
 
 
 L4::Cap<L4::Thread>
-Sched_proxy::received_thread(L4::Snd_fpage const &fp)
+Sched_proxy::received_thread(L4::Ipc::Snd_fpage const &fp)
 {
   if (!fp.cap_received())
     return L4::Cap<L4::Thread>::Invalid;
index 34806d8c0a66c1c1b47fb82dbcc400a34a720f29..4d0d19969da55e5f2aaacd5ee097314725f4ea5d 100644 (file)
@@ -27,13 +27,13 @@ public:
 
   int idle_time(l4_sched_cpu_set_t const &cpus);
 
-  int dispatch(l4_umword_t o, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t o, L4::Ipc::Iostream &ios)
   { return scheduler_dispatch(o, ios); }
 
   void set_prio(unsigned offs, unsigned limit)
   { _prio_offset = offs; _prio_limit = limit; }
 
-  L4::Cap<L4::Thread> received_thread(L4::Snd_fpage const &fp);
+  L4::Cap<L4::Thread> received_thread(L4::Ipc::Snd_fpage const &fp);
 
   void restrict_cpus(l4_umword_t cpus);
 
index edb2f0a82827ec694d474af02fa3e9b74ad19576..be9cbccb628490914fb4d094c9c40cdefcc86fe6 100644 (file)
@@ -20,6 +20,6 @@ L4_CV void LOG_log(const char *function, const char *format, ...)
 L4_CV void LOG_logl(const char *file, int line, const char *function,
                     const char *format, ...)
   __attribute__((format(printf, 4, 5)));
-void LOG_flush(void);
+L4_CV void LOG_flush(void);
 
 EXTERN_C_END
index 92f3b1680bab05eb181548f130f1da7b9fecccc4..1407b8856a8c3ee77f6de93617a179d81a78ade9 100644 (file)
 #include <string.h>
 #include <stdarg.h>
 
-void LOG_flush(void)
+L4_CV void LOG_flush(void)
 {
   fflush(NULL);
 }
 
-void LOG_printf(const char *format, ...)
+L4_CV void LOG_printf(const char *format, ...)
 {
   va_list list;
 
@@ -27,12 +27,12 @@ void LOG_printf(const char *format, ...)
   va_end(list);
 }
 
-void LOG_vprintf(const char *format, va_list list)
+L4_CV void LOG_vprintf(const char *format, va_list list)
 {
   vprintf(format, list);
 }
 
-void LOG_log(const char *function, const char *format, ...)
+L4_CV void LOG_log(const char *function, const char *format, ...)
 {
   va_list list;
 
@@ -44,7 +44,7 @@ void LOG_log(const char *function, const char *format, ...)
 }
 
 
-void LOG_logl(const char *file, int line, const char *function,
+L4_CV void LOG_logl(const char *file, int line, const char *function,
               const char *format, ...)
 {
   va_list list;
index f1202224b47991ca19af0ab3db5189dd5c0a1b49..3e067e288a2b10ad65ba32b49d99e0b2d37ebf24 100644 (file)
@@ -328,7 +328,7 @@ Client_fb::refresh(int x, int y, int w, int h)
 }
 
 int
-Client_fb::dispatch(l4_umword_t obj, L4::Ipc_iostream &s)
+Client_fb::dispatch(l4_umword_t obj, L4::Ipc::Iostream &s)
 {
   l4_msgtag_t tag;
   s >> tag;
index 902871ea9bc3b12395d1d5cebd4b960d8edd9d04..f15a9fb2005b7163207de58ffdce2470498b9d7b 100644 (file)
@@ -57,7 +57,7 @@ public:
   void handle_event(L4Re::Event_buffer::Event const &e,
                     Point const &mouse);
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &s);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &s);
   int refresh(int x, int y, int w, int h);
 
   Area visible_size() const;
index 1886a012e6a41c6fe9e949118abcc61c62ced3e4..2c04740f50daaa6001499009f4d4aad85d55416d 100644 (file)
@@ -58,7 +58,7 @@ namespace {
 };
 
 int
-Service::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Service::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index 1ac01aeb32a8cd2d8f22417e87e2f919dcf5c6cb..cf1ed06607b2a118e40ecac29f94f3cdc323343e 100644 (file)
@@ -24,7 +24,7 @@ private:
 protected:
   User_state *ust() const { return _core->user_state(); }
   Registry *reg() const { return _core->registry(); }
-  int create(char const *msg, L4::Ipc_iostream &ios);
+  int create(char const *msg, L4::Ipc::Iostream &ios);
 
 public:
   Service(char const *name) : Plugin(name) {}
@@ -33,7 +33,7 @@ public:
 
   //Canvas *screen() const { return _ust.vstack()->canvas(); }
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   void destroy();
   ~Service();
index 64436ec86dd8884df02e3c68f4d06c3006e1969e..0a7e2e075518836a2855713c003cf154c6d88bde 100644 (file)
@@ -59,7 +59,7 @@ public:
   char const *type() const { return "Mag client"; }
   void start(Core_api *core);
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   void destroy();
 };
 
@@ -85,14 +85,14 @@ private:
   Buffer_vector _buffers;
   View_vector _views;
 
-  int screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
-  int event_dispatch(l4_umword_t, L4::Ipc_iostream &ios);
+  int screen_dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
+  int event_dispatch(l4_umword_t, L4::Ipc::Iostream &ios);
 
 public:
   Mag_goos(Core_api const *core);
 
   void put_event(L4Re::Event_buffer::Event const &ne, bool trigger);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   L4::Cap<void> rcv_cap() const { return _core->rcv_cap(); }
 
@@ -143,7 +143,7 @@ public:
   Client_view(Core_api const *core, Mag_goos *screen);
   virtual ~Client_view();
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   void draw(Canvas *, View_stack const *, Mode) const;
   void handle_event(L4Re::Event_buffer::Event const &e, Point const &mouse);
 
@@ -337,7 +337,7 @@ namespace {
 };
 
 int
-Mag_client::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Mag_client::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -374,7 +374,7 @@ Mag_client::destroy()
 }
 
 int
-Mag_goos::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Mag_goos::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -396,7 +396,7 @@ Mag_goos::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
 
 
 int
-Mag_goos::event_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Mag_goos::event_dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
@@ -411,7 +411,7 @@ Mag_goos::event_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
 }
 
 int
-Mag_goos::screen_dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Mag_goos::screen_dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
   ios >> op;
index 88b22f53dba4d1e1d1e9c756a5477d97d4d6b14e..c518e7251e9f8b003859e6d0a960ae101c38b89f 100644 (file)
@@ -17,7 +17,7 @@ STATIC_PLUGINS += mag-input-event
 STATIC_PLUGINS += mag-client_fb
 STATIC_PLUGINS += mag-mag_client
 
-REQUIRES_LIBS:= libsupc++ libdl mag-gfx lua++
+REQUIRES_LIBS:= libsupc++ libdl mag-gfx lua++ cxx_libc_io cxx_io
 REQUIRES_LIBS += $(STATIC_PLUGINS)
 #LDFLAGS += --export-dynamic
 
index 5e119e8c2d428b904be57174f1a03be9c7b10bbc..0e7d89289c3aa08d3cb03a57f9ebceef63ac0ce4 100644 (file)
@@ -77,7 +77,7 @@ private:
   public:
     explicit Del_handler(Object_gc *gc) : gc(gc) {}
 
-    int dispatch(l4_umword_t, L4::Ipc_iostream &)
+    int dispatch(l4_umword_t, L4::Ipc::Iostream &)
     {
       gc->gc_step();
       return -L4_ENOREPLY;
@@ -123,7 +123,7 @@ public:
   l4_timeout_t timeout()
   { return l4_timeout(L4_IPC_TIMEOUT_0, l4_timeout_abs(to, 8)); }
 
-  void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode reply_mode)
+  void setup_wait(L4::Ipc::Istream &istr, L4::Ipc_svr::Reply_mode reply_mode)
   {
     if (to < l4re_kip()->clock
        && reply_mode == L4::Ipc_svr::Reply_separate)
@@ -137,12 +137,12 @@ public:
     }
 
     istr.reset();
-    istr << L4::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
     l4_timeout_abs(to, 8);
   }
 
-  L4::Ipc_svr::Reply_mode before_reply(long, L4::Ipc_iostream &)
+  L4::Ipc_svr::Reply_mode before_reply(long, L4::Ipc::Iostream &)
   {
     if (to < l4re_kip()->clock)
       return L4::Ipc_svr::Reply_separate;
index 500a2b432f61b050e08d71e8821411135c9c4c7d..5c77922fd4bfdab934fbef6dea5c9f3d2560724d 100644 (file)
@@ -16,7 +16,7 @@ namespace Mag_server {
 namespace {
   class Trash : public L4::Server_object
   {
-    int dispatch(l4_umword_t, L4::Ipc_iostream &)
+    int dispatch(l4_umword_t, L4::Ipc::Iostream &)
     {
       printf("GOT: stale request, drop it\n");
       return -L4_EINVAL;
index f886584fa8ff03f0f494abaff09f1047d58aae08..c3cf577cd187a40669f98c98b9d48c0c4e9a545f 100644 (file)
@@ -154,7 +154,7 @@ public:
 };
 
 int
-Allocator::disp_factory(l4_umword_t, L4::Ipc_iostream &ios)
+Allocator::disp_factory(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   L4::Factory::Proto o;
   ios >> o;
@@ -285,7 +285,7 @@ class Moe_allocator :
 {};
 
 int
-Allocator::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Allocator::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   L4::Opcode op;
 
index 84527cb4063c629b57a52c0b3f2f13efcb662cfe..8b6a59ffba47b8f6aa0358781426c6dc3ec5c252 100644 (file)
@@ -37,8 +37,8 @@ public:
 
   virtual ~Allocator();
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
-  int disp_factory(l4_umword_t, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
+  int disp_factory(l4_umword_t, L4::Ipc::Iostream &ios);
 
   void *operator new (size_t size, Moe::Quota *q, size_t limit);
   void operator delete (void *m) throw();
index 85752ddc31c80cc1a233c2b4a57c8d3ebcdc7cb4..8cd6e1b0ccd51122222251fc973062dade650e4a 100644 (file)
@@ -18,7 +18,7 @@ using L4Re::Dataspace;
 
 
 int
-App_task::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+App_task::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index fa9b60de65c6134a3804c441d4c850133f83f26c..00c91aedb361d3c900789f37732a32cdb7f42506 100644 (file)
@@ -38,7 +38,7 @@ public:
   Allocator *allocator() const { return _alloc; }
   void set_allocator(Allocator *a) { _alloc = a; }
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 
   Region_map *rm() { return &_rm; }
index 4f8ceb505da7d4b614d1f04d1c9d9ddebe6815ac..43ce0325ff8fd640b31486c6e6696ae909e77610 100644 (file)
@@ -28,9 +28,9 @@ using cxx::min;
 
 int
 Moe::Dataspace::map(l4_addr_t offs, l4_addr_t hot_spot, bool _rw,
-                    l4_addr_t min, l4_addr_t max, L4::Snd_fpage &memory)
+                    l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &memory)
 {
-  memory = L4::Snd_fpage();
+  memory = L4::Ipc::Snd_fpage();
 
   offs     = l4_trunc_page(offs);
   hot_spot = l4_trunc_page(hot_spot);
@@ -49,19 +49,19 @@ Moe::Dataspace::map(l4_addr_t offs, l4_addr_t hot_spot, bool _rw,
   if (adr.is_nil())
     return -L4_EPERM;
 
-  memory = L4::Snd_fpage(adr.fp(), hot_spot, L4::Snd_fpage::Map,
-                         (L4::Snd_fpage::Cacheopt)((_flags >> 12) & (7 << 4)));
+  memory = L4::Ipc::Snd_fpage(adr.fp(), hot_spot, L4::Ipc::Snd_fpage::Map,
+                         (L4::Ipc::Snd_fpage::Cacheopt)((_flags >> 12) & (7 << 4)));
 
   return L4_EOK;
 }
 
 inline
-L4::Ipc_ostream &operator << (L4::Ipc_ostream &s,
+L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s,
                               L4Re::Dataspace::Stats const &st)
 { s.put(st); return s; }
 
 int
-Moe::Dataspace::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Moe::Dataspace::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
@@ -86,7 +86,7 @@ Moe::Dataspace::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
        bool read_only = !is_writable() || !(obj & L4_FPAGE_X);
        l4_addr_t offset, spot;
        unsigned long flags;
-       L4::Snd_fpage fp;
+       L4::Ipc::Snd_fpage fp;
        ios >> offset >> spot >> flags;
 #if 0
        L4::cout << "MAPrq: " << L4::hex << offset << ", " << spot << ", "
@@ -138,7 +138,7 @@ Moe::Dataspace::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
        Moe::Dataspace *src = 0;
        l4_addr_t src_offs;
        unsigned long sz;
-       L4::Snd_fpage src_cap;
+       L4::Ipc::Snd_fpage src_cap;
 
        ios >> dst_offs >> src_offs >> sz >> src_cap;
 
index 0c311a7d9f9eb1f3a9df48a05fb20870fb194a10..9169f0143527649ab0143d859782a95fa21e806c 100644 (file)
@@ -99,15 +99,15 @@ public:
   { return offset < round_size(); }
 
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   int map(l4_addr_t offs, l4_addr_t spot, bool rw,
-          l4_addr_t min, l4_addr_t max, L4::Snd_fpage &memory);
+          l4_addr_t min, l4_addr_t max, L4::Ipc::Snd_fpage &memory);
   int stats(L4Re::Dataspace::Stats &stats);
   //int copy_in(unsigned long dst_offs, Dataspace *src, unsigned long src_offs,
   //    unsigned long size);
   virtual int phys(l4_addr_t offset, l4_addr_t &phys_addr, l4_size_t &phys_size) throw();
 
-  int dispatch(unsigned long obj, unsigned long op, L4::Ipc_iostream &ios);
+  int dispatch(unsigned long obj, unsigned long op, L4::Ipc::Iostream &ios);
 
 private:
   unsigned long _size;
index 0a98135efcd3a88ca42c517a1179151b8fead579..7b0f0dfd195992abf7cfdd975e13fe5adb78d919 100644 (file)
@@ -90,7 +90,7 @@ void Pbuf::outnstring(char const *str, unsigned long len)
 }
 
 int
-Moe::Log::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Moe::Log::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   enum { Max_tag = 8 };
   l4_msgtag_t tag;
@@ -113,7 +113,7 @@ Moe::Log::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
 
   static Pbuf ob;
 
-  ios >> L4::ipc_buf_cp_in(msg, len_msg);
+  ios >> L4::Ipc::Buf_cp_in<char>(msg, len_msg);
 
   while (len_msg > 0 && msg[0])
     {
index 11768fd115a9d22babe5b5d24dbb7a2d3f92c515..e0530cc145cb0df2568e4dd2d2b5c2b86609937b 100644 (file)
@@ -32,7 +32,7 @@ public:
   char const *tag() const { return _tag; }
   unsigned char color() const { return _color; }
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   virtual ~Log() {}
 
index 81bafd6e2457f73ec5799c180984a2bb58090478..412e39dc82dcbb1d781e77c9d72dfefb36a5a8df 100644 (file)
@@ -265,11 +265,11 @@ class Loop_hooks :
   public L4::Ipc_svr::Compound_reply
 {
 public:
-  static void setup_wait(L4::Ipc_istream &istr, L4::Ipc_svr::Reply_mode)
+  static void setup_wait(L4::Ipc::Istream &istr, L4::Ipc_svr::Reply_mode)
   {
     GC_collect_a_little();
     istr.reset();
-    istr << L4::Small_buf(Rcv_cap << L4_CAP_SHIFT,  L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(Rcv_cap << L4_CAP_SHIFT,  L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 };
@@ -281,7 +281,7 @@ private:
   Reg r;
 
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
   {
     l4_msgtag_t tag;
     ios >> tag;
index b44c5ca91a4f65512027f49f12617a57fa78c3ab..9569bee1894567f59d08b32717c2bb8b42f958c3 100644 (file)
@@ -85,7 +85,7 @@ Name_space::free_dynamic_entry(Names::Entry *n)
 }
 
 int
-Name_space::get_capability(L4::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
+Name_space::get_capability(L4::Ipc::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
                            L4::Server_object **lo)
 {
   L4::Cap<void> rcv_cap(Rcv_cap << L4_CAP_SHIFT);
index 5cf8626e61cd4430b7eefa93bf778ecf4b711cfc..4e9b07d33c3c237c2aa75cd1d84db4a87de04472 100644 (file)
@@ -43,7 +43,7 @@ class Name_space : public Moe::Server_object,
 {
 public:
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
   {
     enum { Max_name = 2048 };
     static char buffer[Max_name];
@@ -55,7 +55,7 @@ public:
   ~Name_space();
 
   // server support ----------------------------------------
-  int get_capability(L4::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
+  int get_capability(L4::Ipc::Snd_fpage const &cap_fp, L4::Cap<void> *cap,
                      L4::Server_object **lo);
   int save_capability(L4::Cap<void> *cap);
   void free_capability(L4::Cap<void> cap);
index 2b41c2acb9bbfde86f554f2c5ad9ea7b0bf21e0d..4f9043989bf95a3da576e890fbe525895967f41e 100644 (file)
@@ -45,7 +45,7 @@ Region_map::Region_map()
 
 int Region_ops::map(Region_handler const *h, l4_addr_t adr,
                     L4Re::Util::Region const &r, bool writable,
-                    L4::Snd_fpage *result)
+                    L4::Ipc::Snd_fpage *result)
 {
   l4_addr_t offs = adr - r.start();
   offs = l4_trunc_page(offs);
@@ -56,7 +56,7 @@ int Region_ops::map(Region_handler const *h, l4_addr_t adr,
     Dbg(Dbg::Warn).printf("WARNING: "
          "Writable mapping request on read-only region at %lx!\n",
          adr);
-  *result = L4::Snd_fpage(h->memory()->address(offs + h->offset(), rw, adr,
+  *result = L4::Ipc::Snd_fpage(h->memory()->address(offs + h->offset(), rw, adr,
                           r.start(), r.end()).fp(), offs + r.start());
 
   return L4_EOK;
@@ -77,7 +77,7 @@ class Rm_server
 public:
   typedef Moe::Dataspace const *Dataspace;
   enum { Have_find = false };
-  static int validate_ds(L4::Snd_fpage const &ds_cap,
+  static int validate_ds(L4::Ipc::Snd_fpage const &ds_cap,
                          unsigned flags, Dataspace *ds)
   {
     if (flags & L4Re::Rm::Pager)
@@ -104,7 +104,7 @@ public:
 };
 
 int
-Region_map::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Region_map::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   Dbg warn(Dbg::Warn, "WARN");
   l4_msgtag_t tag;
index d6fc35fb8532ecf59571214d473dcf0e8eef30ed..c29cef87ae9a79af59dc236f346a7193b2a1f568 100644 (file)
@@ -25,10 +25,10 @@ typedef L4Re::Util::Region_handler<Moe::Dataspace const *, Region_ops> Region_ha
 class Region_ops
 {
 public:
-  typedef L4::Snd_fpage Map_result;
+  typedef L4::Ipc::Snd_fpage Map_result;
   static int map(Region_handler const *h, l4_addr_t adr,
                  L4Re::Util::Region const &r, bool writable,
-                 L4::Snd_fpage *result);
+                 L4::Ipc::Snd_fpage *result);
   static void unmap(Region_handler const * /*h*/, l4_addr_t /*vaddr*/,
                     l4_addr_t /*offs*/, unsigned long /*size*/)
   {}
@@ -49,7 +49,7 @@ private:
 
 public:
   Region_map();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   virtual ~Region_map() {}
 };
 
index 1df2608444a2d6b2b1dfbfffdc89f5413317c34a..6b4a1396e42923e4e29e31d300e3366b4b83e2e4 100644 (file)
@@ -141,7 +141,7 @@ Sched_proxy::idle_time(l4_sched_cpu_set_t const &)
 
 
 L4::Cap<L4::Thread>
-Sched_proxy::received_thread(L4::Snd_fpage const &fp)
+Sched_proxy::received_thread(L4::Ipc::Snd_fpage const &fp)
 {
   if (!fp.cap_received())
     return L4::Cap<L4::Thread>::Invalid;
index b4ccb54931117764dec66a8037d86db2ef835310..0f10948557622c5a28dd7cef141a009742ac5843 100644 (file)
@@ -28,13 +28,13 @@ public:
 
   int idle_time(l4_sched_cpu_set_t const &cpus);
 
-  int dispatch(l4_umword_t o, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t o, L4::Ipc::Iostream &ios)
   { return scheduler_dispatch(o, ios); }
 
   void set_prio(unsigned offs, unsigned limit)
   { _prio_offset = offs; _prio_limit = limit; }
 
-  L4::Cap<L4::Thread> received_thread(L4::Snd_fpage const &fp);
+  L4::Cap<L4::Thread> received_thread(L4::Ipc::Snd_fpage const &fp);
 
   void restrict_cpus(l4_umword_t cpus);
 
index 06a458056e39064ccde049b07de913e11298f55e..e534b71b77b512f543e3ec58c1176f6484523092 100644 (file)
@@ -42,7 +42,7 @@ public:
   Vesa_fb(l4util_mb_info_t *mbi);
   virtual ~Vesa_fb() {}
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
   { return L4Re::Util::Video::Goos_svr::dispatch(obj, ios); }
 };
 
index 9e8f16989bbabd34dc3ea32fdbd233bc2be6d4f1..6b3a6826707565d49838cb9ecc7648c117a759f2 100644 (file)
@@ -8,7 +8,7 @@ SRC_CC          := remote_mem.cc app_model.cc app_task.cc main.cc \
                   lua_exec.cc lua_factory.cc lua_info.cc server.cc
 OBJS            += ned.lua.bin.o
 
-REQUIRES_LIBS   := libloader l4re-util l4re lua++ libpthread
+REQUIRES_LIBS   := libloader l4re-util l4re lua++ libpthread cxx_libc_io cxx_io
 
 ifeq (1,0)
 DEFINES         += -DUSE_READLINE
index d0580a4852566cc1735509ce1682e13b0fa59484..902c9a082d2992bbebbc970ebb403fcb94a132d2 100644 (file)
@@ -37,7 +37,7 @@ void App_task::operator delete (void *m) throw()
 #endif
 
 int
-App_task::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+App_task::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   (void)obj;
   l4_msgtag_t tag;
index ab7710cdbe8235e2989f113201b0b186280b1de3..6504fd9817bf1f982d96274797abca0fa1e3e5b8 100644 (file)
@@ -66,7 +66,7 @@ public:
 
   //L4::Cap<L4Re::Mem_alloc> allocator() const { return _ma; }
 
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
   L4::Cap<L4Re::Rm> rm() { return _rm.get(); }
   L4::Cap<L4::Task> task_cap() const { return _task.get(); }
index 031664ac2af46c1c66051d284a1aa2a3933e0476..438df6be5ec9cc50c819192184c830c5cebf9861 100644 (file)
@@ -160,7 +160,7 @@ Cap::find_dynamic_type(lua_State *l) const
   using L4Re::Util::Ref_cap;
   Dbg dbg(Dbg::Warn, "lua");
   Ref_cap<L4::Meta>::Cap _meta = L4::cap_cast<L4::Meta>(_c);
-  L4::Ipc_istream res(l4_utcb());
+  L4::Ipc::Istream res(l4_utcb());
   res.tag() = _meta->interface(0);
 
   if (int err = l4_error(res.tag()))
index ea2d00728baceb36d7fa39f5823a203c9d3219e6..ab02e95a91043217d0691ce8ddb6d0a19cb3d4b0 100644 (file)
@@ -33,13 +33,13 @@ namespace Lua { namespace {
 class Observer : public Ned::Server_object
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 static Observer *observer;
 
 int
-Observer::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Observer::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_cap_idx_t thread = L4::Ipc::read<l4_cap_idx_t>(ios);
   App_task *t = (App_task*)L4::Ipc::read<l4_addr_t>(ios);
index c48bdc2f71ad03fb27a64245577fa5c9dc288b56..410e72f97e506059be240da5a7e39c84be7e14f1 100644 (file)
@@ -4,7 +4,7 @@ L4DIR          ?= $(PKGDIR)/../..
 TARGET          = python
 MODE            = shared
 REQUIRES_LIBS   = libpython libc_be_file_stdin \
-                  libc_be_sig libc_be_math readline
+                  libc_be_sig libc_be_math readline cxx_libc_io cxx_io
 PRIVATE_INCDIR  = $(PKGDIR_ABS)/include $(PKGDIR_ABS)/include/ARCH-$(ARCH)
 SRC_CC          = python.cc 
 PRIVATE_INCDIR += $(PKGDIR_ABS)/contrib/Include
index d8f07461319efafe7ed329ee9c726cdcc5198150..f7a9708228bf3a1d7e44b9425d70a685265f8c57 100644 (file)
@@ -62,7 +62,7 @@ muldiv (l4_uint32_t val, l4_uint32_t mul, l4_uint32_t div)
 int
 l4rtc_if_get_offset_call(L4::Cap<void> server, l4_uint32_t *offset)
 {
-  L4::Ipc_iostream _(l4_utcb());
+  L4::Ipc::Iostream _(l4_utcb());
   _ << l4_umword_t(L4RTC_OPCODE_get_offset);
   l4_msgtag_t res = _.call(server.cap());
   if (l4_ipc_error(res, l4_utcb()))
@@ -74,7 +74,7 @@ l4rtc_if_get_offset_call(L4::Cap<void> server, l4_uint32_t *offset)
 int
 l4rtc_if_get_linux_tsc_scaler_call(L4::Cap<void> server, l4_uint32_t *scaler)
 {
-  L4::Ipc_iostream _(l4_utcb());
+  L4::Ipc::Iostream _(l4_utcb());
   _ << l4_umword_t(L4RTC_OPCODE_get_linux_tsc_scaler);
   l4_msgtag_t res = _.call(server.cap());
   if (l4_ipc_error(res, l4_utcb()))
index fb01bfd103ccf97d97da2003cb31d44a86e84171..a1f47f977ffe1f904413d3875d19cf5bd6fbe0eb 100644 (file)
@@ -7,7 +7,7 @@ SRC_CC_amd64    = x86.cc
 SRC_C_x86       = ux.c
 SRC_CC         = main.cc $(SRC_CC_$(ARCH))
 SRC_C          = $(SRC_C_$(ARCH))
-REQUIRES_LIBS   = libio
+REQUIRES_LIBS   = libio cxx_libc_io cxx_io
 LIBS_x86        = -lclxfux.o
 LIBS            = $(LIBS_$(ARCH))
 
index 22785749c1975809a42d458ec1841c10e5978eda..1b36523c86a332f80d44288920c6f331239c0b96 100644 (file)
@@ -63,11 +63,11 @@ l4rtc_if_get_linux_tsc_scaler_component(l4_uint32_t *scaler)
 class Rtc_dispatcher
 {
 public:
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 };
 
 int
-Rtc_dispatcher::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Rtc_dispatcher::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
index 184cc19dd7292a7ff41a0783b5c73ab41e382207..fac6547ca3ee4f6fb7a1ba015de592294a3a4503 100644 (file)
@@ -19,7 +19,6 @@
 #include "factory.h"
 #include "platform.h"
 #include <l4/cxx/exceptions>
-#include <l4/cxx/iostream>
 
 #include <l4/scout-gfx/tick>
 #include <l4/scout-gfx/redraw_manager>
@@ -28,6 +27,8 @@
 #include <l4/scout-gfx/redraw_manager>
 
 #include "browser_window.h"
+#include <iostream>
+#include <l4/cxx/std_exc_io>
 
 using Scout_gfx::Document;
 
@@ -147,8 +148,8 @@ try {
 
   return 0;
 } catch (L4::Runtime_error const &e) {
-    L4::cerr << "Fatal exception: " << e.str() << " '" << e.extra_str()
-             << "'\n" << e;
+    std::cerr << "Fatal exception: " << e.str() << " '" << e.extra_str()
+              << "'\n" << e;
 }
 return 1;
 }
index 0faa7eb6a6a388779d8a0cf171bf989afcd85eec..6bd961f8bbe87f3cd3346e91dba0667c113916e3 100644 (file)
@@ -8,6 +8,8 @@ vpath %.txt $(SRC_DIR)
 
 include $(L4DIR)/mk/prog.mk
 
+$(GENERAL_D_LOC): $(SCOUTDIR)/mk/scout.mk
+
 %.bin.o: %
        @$(GEN_MESSAGE)
        $(VERBOSE)(TARGETDIR=$$PWD && cd $(dir $<) && $(OBJCOPY) -I binary -B $(BFD_ARCH_$(ARCH)) -O $(OFORMAT) $(notdir $<) $$TARGETDIR/$@)
index 59a788bf540de0163aba7f5cc1104cda586b0457..8ca7d55754b6f5185143fa41cb3610643931ed8e 100644 (file)
@@ -32,10 +32,10 @@ class Loop_hooks :
   public L4::Ipc_svr::Compound_reply
 {
 public:
-  void setup_wait(L4::Ipc_istream &istr, bool)
+  void setup_wait(L4::Ipc::Istream &istr, bool)
   {
     istr.reset();
-    istr << L4::Small_buf(srv_rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
+    istr << L4::Ipc::Small_buf(srv_rcv_cap.cap(), L4_RCV_ITEM_LOCAL_ID);
     l4_utcb_br_u(istr.utcb())->bdr = 0;
   }
 };
@@ -69,7 +69,7 @@ public:
   int handle_irq();
 
   bool init();
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 private:
   bool _running;
@@ -189,7 +189,7 @@ Serial_drv::init()
 }
 
 int
-Serial_drv::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Serial_drv::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t tag;
   ios >> tag;
index d0cc2ac1e6815f7b0f6fdc718c577a6108139252..1d57b0697905d8aa792270b895ab64c1538c9f8f 100644 (file)
@@ -1,9 +1,8 @@
-# directories we need to know
-PKGDIR ?=       ../..
-L4DIR ?=        $(PKGDIR)/../..
+PKGDIR        ?= ../..
+L4DIR         ?= $(PKGDIR)/../..
 
-SRC_C =                slab.c
+TARGET         = libslab.a libslab.so
+SRC_C          = slab.c
 PRIVATE_INCDIR = $(SRC_DIR)/../include
-TARGET =       libslab.a
 
 include $(L4DIR)/mk/lib.mk
index 53e4fd110ab2031d66e2e4a3156aa149260ff65a..b0f4b71de02461511847cded1f6be955b71ae1ec 100644 (file)
@@ -231,7 +231,7 @@ relink(struct l4slab_slab *slab,
  * sweet-spot in the trade-off between internal and external fragmentation".
  */
 /*****************************************************************************/
-int
+L4_CV int
 l4slab_cache_init(l4slab_cache_t * cache, l4_size_t obj_size,
                   unsigned int max_free, l4slab_grow_fn_t grow_fn,
                   l4slab_release_fn_t release_fn)
@@ -288,7 +288,7 @@ l4slab_cache_init(l4slab_cache_t * cache, l4_size_t obj_size,
  * otherwise it has no effect.
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_destroy(l4slab_cache_t * cache)
 {
   l4slab_slab_t * slabs[3] = { cache->slabs_full, cache->slabs_part, cache->slabs_free };
@@ -324,7 +324,7 @@ l4slab_destroy(l4slab_cache_t * cache)
  * \return pointer to object, NULL if allocation failed.
  */
 /*****************************************************************************/
-void *
+L4_CV void *
 l4slab_alloc(l4slab_cache_t * cache)
 {
   int ret;
@@ -393,7 +393,7 @@ l4slab_alloc(l4slab_cache_t * cache)
  * \param  objp          Pointer to object
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_free(l4slab_cache_t * cache, void * objp)
 {
   l4slab_slab_t * slab;
@@ -451,7 +451,7 @@ l4slab_free(l4slab_cache_t * cache, void * objp)
  * Add the slab to the slab cache.
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_add_slab(l4slab_cache_t * cache, void * buffer, void * data)
 {
   /* sanity checks */
@@ -477,7 +477,7 @@ l4slab_add_slab(l4slab_cache_t * cache, void * buffer, void * data)
  * \param  data          Application data pointer
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_set_data(l4slab_cache_t * cache, void * data)
 {
   if (cache == NULL)
@@ -496,7 +496,7 @@ l4slab_set_data(l4slab_cache_t * cache, void * data)
  *         data pointer set.
  */
 /*****************************************************************************/
-void *
+L4_CV void *
 l4slab_get_data(l4slab_cache_t * cache)
 {
   if (cache == NULL)
@@ -513,7 +513,7 @@ l4slab_get_data(l4slab_cache_t * cache)
  * \param  dump_free     Dump free list of slabs
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_dump_cache(l4slab_cache_t * cache, int dump_free)
 {
   l4slab_slab_t * slabs[3] = { cache->slabs_full, cache->slabs_part, cache->slabs_free };
@@ -561,7 +561,7 @@ l4slab_dump_cache(l4slab_cache_t * cache, int dump_free)
  * \param  cache         Cache descriptor
  */
 /*****************************************************************************/
-void
+L4_CV void
 l4slab_dump_cache_free(l4slab_cache_t * cache)
 {
   l4slab_slab_t * slab;
index c12a7a2202e09eabb5cd74b5065ea29ae55e2d81..1544ee45cce61b5262c06eb7bb11d04910badb30 100644 (file)
@@ -3,7 +3,7 @@ L4DIR           ?= $(PKGDIR)/../..
 
 TARGET         = spafs_prov
 SRC_CC         = main.cc
-REQUIRES_LIBS   = l4util libsupc++
+REQUIRES_LIBS   = l4util libsupc++ cxx_libc_io cxx_io
 
 include $(L4DIR)/mk/prog.mk
 
index 8420f6aa9fac01e74c7d4307e95fe55da668be21..9b7a2613ca7647da3785a85282b0ff5a4cdb4772 100644 (file)
@@ -55,14 +55,14 @@ class Fprov_server : public L4::Server_object
 
 public:
   Fprov_server(L4::Cap<L4Re::Dataspace> ds);
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
 
 private:
   enum {
     Max_filename_len = 1024,
   };
 
-  int get_file(char const *filename, L4::Ipc_iostream &ios);
+  int get_file(char const *filename, L4::Ipc::Iostream &ios);
 
   L4::Cap<L4Re::Dataspace> _ds;
   l4_addr_t _addr;
@@ -105,7 +105,7 @@ Fprov_server::Fprov_server(L4::Cap<L4Re::Dataspace> ds)
 }
 
 int
-Fprov_server::get_file(char const *filename, L4::Ipc_iostream &ios)
+Fprov_server::get_file(char const *filename, L4::Ipc::Iostream &ios)
 {
   //printf("Open file:%s\n", filename);
   Dir_entry *dir_entry = 0;
@@ -130,7 +130,7 @@ Fprov_server::get_file(char const *filename, L4::Ipc_iostream &ios)
     {
       if (verbose)
         printf("file already open: <%s>\n", filename);
-      ios << L4::Snd_fpage(dir_entry->ds.fpage(L4_FPAGE_RO));
+      ios << L4::Ipc::Snd_fpage(dir_entry->ds.fpage(L4_FPAGE_RO));
       return 0;
     }
 
@@ -157,13 +157,13 @@ Fprov_server::get_file(char const *filename, L4::Ipc_iostream &ios)
     }
   dir_entry->ds = file_ds;
 
-  ios << L4::Snd_fpage(file_ds.fpage(L4_FPAGE_RO));
+  ios << L4::Ipc::Snd_fpage(file_ds.fpage(L4_FPAGE_RO));
 
   return 0;
 }
 
 int
-Fprov_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Fprov_server::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
@@ -181,15 +181,9 @@ Fprov_server::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
     {
     case L4Re::Namespace_::Query:
         {
-          char const *filenamep = 0;
           char filename[Max_filename_len];
           unsigned long len = Max_filename_len;
-          ios >> L4::ipc_buf_in(filenamep, len);
-
-          // copy out of utcb
-          if (Max_filename_len - 1 < len)
-            len = Max_filename_len - 1;
-          memcpy(filename, filenamep, len);
+          ios >> L4::Ipc::Buf_cp_in<char>(filename, len);
           filename[len] = 0;
 
           return get_file(filename, ios);
@@ -213,7 +207,7 @@ class Fprov_service : public L4::Server_object
 
 public:
   Fprov_service() {};
-  int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios);
+  int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios);
   static Fprov_server *create_server(const char *filename);
 };
 
@@ -235,7 +229,7 @@ Fprov_service::create_server(const char *filename)
 }
 
 int
-Fprov_service::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
+Fprov_service::dispatch(l4_umword_t, L4::Ipc::Iostream &ios)
 {
   l4_msgtag_t t;
   ios >> t;
@@ -250,7 +244,6 @@ Fprov_service::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
       return -L4_EBADPROTO;
     }
 
-  
   switch (L4::Ipc::read<L4::Factory::Proto>(ios))
     {
     case L4Re::Namespace::Protocol:
@@ -259,7 +252,7 @@ Fprov_service::dispatch(l4_umword_t, L4::Ipc_iostream &ios)
          unsigned long name_size = Name_size;
          static char config[Name_size];
 
-         ios >> L4::ipc_buf_cp_in(config, name_size);
+         ios >> L4::Ipc::Buf_cp_in<char>(config, name_size);
          config[name_size] = 0;
 
          Fprov_server *server = Fprov_service::create_server(config);
index f0944ea2c6624040b274b04c463ab7a8ddbd9d4e..86680df6545e084e6d15a7c4765c9f6274ef0fa3 100644 (file)
@@ -1,4 +1,4 @@
 
 
 The contrib directory contains the unmodified contents of
-sqlite-autoconf-3070602.tar.gz
+sqlite-autoconf-3070701.tar.gz
index 26f82cc7305315af09a4d8f6eb0aa98eacc768b3..d4f1386f37922de5f641db03306ab76b66fc0f7c 100644 (file)
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005  Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
 
 
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
-top_builddir = .
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
 am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-INSTALL = @INSTALL@
 install_sh_DATA = $(install_sh) -c -m 644
 install_sh_PROGRAM = $(install_sh) -c
 install_sh_SCRIPT = $(install_sh) -c
@@ -40,56 +38,73 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 bin_PROGRAMS = sqlite3$(EXEEXT)
+subdir = .
 DIST_COMMON = README $(am__configure_deps) $(include_HEADERS) \
        $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
        $(srcdir)/sqlite3.pc.in $(top_srcdir)/configure INSTALL \
        config.guess config.sub depcomp install-sh ltmain.sh missing
-subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
- configure.lineno configure.status.lineno
+ configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_CLEAN_FILES = sqlite3.pc
+CONFIG_CLEAN_VPATH_FILES =
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
     *) f=$$p;; \
   esac;
-am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
        "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(pkgconfigdir)" \
        "$(DESTDIR)$(includedir)"
-libLTLIBRARIES_INSTALL = $(INSTALL)
 LTLIBRARIES = $(lib_LTLIBRARIES)
 libsqlite3_la_LIBADD =
 am_libsqlite3_la_OBJECTS = sqlite3.lo
 libsqlite3_la_OBJECTS = $(am_libsqlite3_la_OBJECTS)
-binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+libsqlite3_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(libsqlite3_la_LDFLAGS) $(LDFLAGS) -o $@
 PROGRAMS = $(bin_PROGRAMS)
 am_sqlite3_OBJECTS = shell.$(OBJEXT)
 sqlite3_OBJECTS = $(am_sqlite3_OBJECTS)
-DEFAULT_INCLUDES = -I. -I$(srcdir)
+DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
+am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
        $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
-       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
-       $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 CCLD = $(CC)
-LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
-       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
 SOURCES = $(libsqlite3_la_SOURCES) $(sqlite3_SOURCES)
 DIST_SOURCES = $(libsqlite3_la_SOURCES) $(sqlite3_SOURCES)
 man1dir = $(mandir)/man1
 NROFF = nroff
 MANS = $(man_MANS)
-pkgconfigDATA_INSTALL = $(INSTALL_DATA)
 DATA = $(pkgconfig_DATA)
-includeHEADERS_INSTALL = $(INSTALL_HEADER)
 HEADERS = $(include_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -97,16 +112,14 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
 am__remove_distdir = \
-  { test ! -d $(distdir) \
-    || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
-         && rm -fr $(distdir); }; }
+  { test ! -d "$(distdir)" \
+    || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr "$(distdir)"; }; }
 DIST_ARCHIVES = $(distdir).tar.gz
 GZIP_ENV = --best
 distuninstallcheck_listfiles = find . -type f -print
 distcleancheck_listfiles = find . -type f -print
 ACLOCAL = @ACLOCAL@
-AMDEP_FALSE = @AMDEP_FALSE@
-AMDEP_TRUE = @AMDEP_TRUE@
 AMTAR = @AMTAR@
 AR = @AR@
 AUTOCONF = @AUTOCONF@
@@ -119,57 +132,62 @@ CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
 DYNAMIC_EXTENSION_FLAGS = @DYNAMIC_EXTENSION_FLAGS@
-ECHO = @ECHO@
 ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
-F77 = @F77@
-FFLAGS = @FFLAGS@
+FGREP = @FGREP@
 GREP = @GREP@
+INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
 MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
 PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
 PACKAGE_NAME = @PACKAGE_NAME@
 PACKAGE_STRING = @PACKAGE_STRING@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 RANLIB = @RANLIB@
 READLINE_LIBS = @READLINE_LIBS@
+SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 STRIP = @STRIP@
 THREADSAFE_FLAGS = @THREADSAFE_FLAGS@
 VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
 ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
-am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
-am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -181,6 +199,7 @@ build_alias = @build_alias@
 build_cpu = @build_cpu@
 build_os = @build_os@
 build_vendor = @build_vendor@
+builddir = @builddir@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
@@ -199,6 +218,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
@@ -208,8 +228,12 @@ program_transform_name = @program_transform_name@
 psdir = @psdir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
 AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE
 lib_LTLIBRARIES = libsqlite3.la
 libsqlite3_la_SOURCES = sqlite3.c
@@ -232,15 +256,15 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
            *$$dep*) \
-             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
-             cd $(srcdir) && $(AUTOMAKE) --foreign  \
+             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+             $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
                && exit 0; \
              exit 1;; \
          esac; \
        done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  Makefile'; \
-       cd $(top_srcdir) && \
-         $(AUTOMAKE) --foreign  Makefile
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
@@ -256,28 +280,33 @@ $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENC
        $(SHELL) ./config.status --recheck
 
 $(top_srcdir)/configure:  $(am__configure_deps)
-       cd $(srcdir) && $(AUTOCONF)
+       $(am__cd) $(srcdir) && $(AUTOCONF)
 $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
-       cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+       $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
 sqlite3.pc: $(top_builddir)/config.status $(srcdir)/sqlite3.pc.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
 install-libLTLIBRARIES: $(lib_LTLIBRARIES)
        @$(NORMAL_INSTALL)
-       test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
-       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+       test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       list2=; for p in $$list; do \
          if test -f $$p; then \
-           f=$(am__strip_dir) \
-           echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
-           $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+           list2="$$list2 $$p"; \
          else :; fi; \
-       done
+       done; \
+       test -z "$$list2" || { \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+       }
 
 uninstall-libLTLIBRARIES:
        @$(NORMAL_UNINSTALL)
-       @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
-         p=$(am__strip_dir) \
-         echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
-         $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
        done
 
 clean-libLTLIBRARIES:
@@ -289,38 +318,53 @@ clean-libLTLIBRARIES:
          rm -f "$${dir}/so_locations"; \
        done
 libsqlite3.la: $(libsqlite3_la_OBJECTS) $(libsqlite3_la_DEPENDENCIES) 
-       $(LINK) -rpath $(libdir) $(libsqlite3_la_LDFLAGS) $(libsqlite3_la_OBJECTS) $(libsqlite3_la_LIBADD) $(LIBS)
+       $(libsqlite3_la_LINK) -rpath $(libdir) $(libsqlite3_la_OBJECTS) $(libsqlite3_la_LIBADD) $(LIBS)
 install-binPROGRAMS: $(bin_PROGRAMS)
        @$(NORMAL_INSTALL)
-       test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
-       @list='$(bin_PROGRAMS)'; for p in $$list; do \
-         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-         if test -f $$p \
-            || test -f $$p1 \
-         ; then \
-           f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
-          echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
-          $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
-         else :; fi; \
-       done
+       test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p || test -f $$p1; \
+         then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+           } \
+       ; done
 
 uninstall-binPROGRAMS:
        @$(NORMAL_UNINSTALL)
-       @list='$(bin_PROGRAMS)'; for p in $$list; do \
-         f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
-         echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
-         rm -f "$(DESTDIR)$(bindir)/$$f"; \
-       done
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(bindir)" && rm -f $$files
 
 clean-binPROGRAMS:
-       @list='$(bin_PROGRAMS)'; for p in $$list; do \
-         f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
-         echo " rm -f $$p $$f"; \
-         rm -f $$p $$f ; \
-       done
+       @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
 sqlite3$(EXEEXT): $(sqlite3_OBJECTS) $(sqlite3_DEPENDENCIES) 
        @rm -f sqlite3$(EXEEXT)
-       $(LINK) $(sqlite3_LDFLAGS) $(sqlite3_OBJECTS) $(sqlite3_LDADD) $(LIBS)
+       $(LINK) $(sqlite3_OBJECTS) $(sqlite3_LDADD) $(LIBS)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
@@ -332,22 +376,22 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite3.Plo@am__quote@
 
 .c.o:
-@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(COMPILE) -c $<
 
 .c.obj:
-@am__fastdepCC_TRUE@   if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
-@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
 
 .c.lo:
-@am__fastdepCC_TRUE@   if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@   then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
@@ -359,171 +403,190 @@ clean-libtool:
        -rm -rf .libs _libs
 
 distclean-libtool:
-       -rm -f libtool
-uninstall-info-am:
-install-man1: $(man1_MANS) $(man_MANS)
+       -rm -f libtool config.lt
+install-man1: $(man_MANS)
        @$(NORMAL_INSTALL)
-       test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)"
-       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
-       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-       for i in $$l2; do \
-         case "$$i" in \
-           *.1*) list="$$list $$i" ;; \
-         esac; \
+       test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       { for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+         fi; \
        done; \
-       for i in $$list; do \
-         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
-         else file=$$i; fi; \
-         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-         case "$$ext" in \
-           1*) ;; \
-           *) ext='1' ;; \
-         esac; \
-         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-         inst=`echo $$inst | sed -e 's/^.*\///'`; \
-         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-         echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
-         $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
-       done
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+       done; }
+
 uninstall-man1:
        @$(NORMAL_UNINSTALL)
-       @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
-       l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
-       for i in $$l2; do \
-         case "$$i" in \
-           *.1*) list="$$list $$i" ;; \
-         esac; \
-       done; \
-       for i in $$list; do \
-         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
-         case "$$ext" in \
-           1*) ;; \
-           *) ext='1' ;; \
-         esac; \
-         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
-         inst=`echo $$inst | sed -e 's/^.*\///'`; \
-         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
-         echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
-         rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
-       done
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       test -z "$$files" || { \
+         echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
+         cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
 install-pkgconfigDATA: $(pkgconfig_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(pkgconfigdir)" || $(mkdir_p) "$(DESTDIR)$(pkgconfigdir)"
-       @list='$(pkgconfig_DATA)'; for p in $$list; do \
+       test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
+       @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+       for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         f=$(am__strip_dir) \
-         echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
-         $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
        done
 
 uninstall-pkgconfigDATA:
        @$(NORMAL_UNINSTALL)
-       @list='$(pkgconfig_DATA)'; for p in $$list; do \
-         f=$(am__strip_dir) \
-         echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
-         rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
-       done
+       @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files
 install-includeHEADERS: $(include_HEADERS)
        @$(NORMAL_INSTALL)
-       test -z "$(includedir)" || $(mkdir_p) "$(DESTDIR)$(includedir)"
-       @list='$(include_HEADERS)'; for p in $$list; do \
+       test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+       @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+       for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         f=$(am__strip_dir) \
-         echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
-         $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+         $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
        done
 
 uninstall-includeHEADERS:
        @$(NORMAL_UNINSTALL)
-       @list='$(include_HEADERS)'; for p in $$list; do \
-         f=$(am__strip_dir) \
-         echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
-         rm -f "$(DESTDIR)$(includedir)/$$f"; \
-       done
+       @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(includedir)" && rm -f $$files
 
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
        list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
        unique=`for i in $$list; do \
            if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
          done | \
-         $(AWK) '    { files[$$0] = 1; } \
-              END { for (i in files) print i; }'`; \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
        mkid -fID $$unique
 tags: TAGS
 
 TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
                $(TAGS_FILES) $(LISP)
-       tags=; \
+       set x; \
        here=`pwd`; \
        list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
        unique=`for i in $$list; do \
            if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
          done | \
-         $(AWK) '    { files[$$0] = 1; } \
-              END { for (i in files) print i; }'`; \
-       if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
          test -n "$$unique" || unique=$$empty_fix; \
-         $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-           $$tags $$unique; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
        fi
 ctags: CTAGS
 CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
                $(TAGS_FILES) $(LISP)
-       tags=; \
-       here=`pwd`; \
        list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
        unique=`for i in $$list; do \
            if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
          done | \
-         $(AWK) '    { files[$$0] = 1; } \
-              END { for (i in files) print i; }'`; \
-       test -z "$(CTAGS_ARGS)$$tags$$unique" \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
          || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$tags $$unique
+            $$unique
 
 GTAGS:
        here=`$(am__cd) $(top_builddir) && pwd` \
-         && cd $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) $$here
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
 
 distclean-tags:
        -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
+       @list='$(MANS)'; if test -n "$$list"; then \
+         list=`for p in $$list; do \
+           if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+           if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+         if test -n "$$list" && \
+           grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+           echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+           grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+           echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+           echo "       typically \`make maintainer-clean' will remove them" >&2; \
+           exit 1; \
+         else :; fi; \
+       else :; fi
        $(am__remove_distdir)
-       mkdir $(distdir)
-       $(mkdir_p) $(distdir)/.
-       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
-       list='$(DISTFILES)'; for file in $$list; do \
-         case $$file in \
-           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
-           $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
-         esac; \
+       test -d "$(distdir)" || mkdir "$(distdir)"
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
          if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
-         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
-           dir="/$$dir"; \
-           $(mkdir_p) "$(distdir)$$dir"; \
-         else \
-           dir=''; \
-         fi; \
          if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
            if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
            fi; \
-           cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
          else \
-           test -f $(distdir)/$$file \
-           || cp -p $$d/$$file $(distdir)/$$file \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
            || exit 1; \
          fi; \
        done
-       -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+       -test -n "$(am__skip_mode_fix)" \
+       || find "$(distdir)" -type d ! -perm -755 \
+               -exec chmod u+rwx,go+rx {} \; -o \
          ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
          ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
-         ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
-       || chmod -R a+r $(distdir)
+         ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+       || chmod -R a+r "$(distdir)"
 dist-gzip: distdir
        tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
        $(am__remove_distdir)
@@ -532,6 +595,14 @@ dist-bzip2: distdir
        tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
        $(am__remove_distdir)
 
+dist-lzma: distdir
+       tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+       $(am__remove_distdir)
+
+dist-xz: distdir
+       tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+       $(am__remove_distdir)
+
 dist-tarZ: distdir
        tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
        $(am__remove_distdir)
@@ -555,13 +626,17 @@ dist dist-all: distdir
 distcheck: dist
        case '$(DIST_ARCHIVES)' in \
        *.tar.gz*) \
-         GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
        *.tar.bz2*) \
-         bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+         bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+       *.tar.lzma*) \
+         lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
+       *.tar.xz*) \
+         xz -dc $(distdir).tar.xz | $(am__untar) ;;\
        *.tar.Z*) \
          uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
        *.shar.gz*) \
-         GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
        *.zip*) \
          unzip $(distdir).zip ;;\
        esac
@@ -569,9 +644,11 @@ distcheck: dist
        mkdir $(distdir)/_build
        mkdir $(distdir)/_inst
        chmod a-w $(distdir)
+       test -d $(distdir)/_build || exit 0; \
        dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
          && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
-         && cd $(distdir)/_build \
+         && am__cwd=`pwd` \
+         && $(am__cd) $(distdir)/_build \
          && ../configure --srcdir=.. --prefix="$$dc_install_base" \
            $(DISTCHECK_CONFIGURE_FLAGS) \
          && $(MAKE) $(AM_MAKEFLAGS) \
@@ -593,13 +670,15 @@ distcheck: dist
          && rm -rf "$$dc_destdir" \
          && $(MAKE) $(AM_MAKEFLAGS) dist \
          && rm -rf $(DIST_ARCHIVES) \
-         && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+         && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+         && cd "$$am__cwd" \
+         || exit 1
        $(am__remove_distdir)
        @(echo "$(distdir) archives ready for distribution: "; \
          list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
-         sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+         sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
 distuninstallcheck:
-       @cd $(distuninstallcheck_dir) \
+       @$(am__cd) '$(distuninstallcheck_dir)' \
        && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
           || { echo "ERROR: files left after uninstall:" ; \
                if test -n "$(DESTDIR)"; then \
@@ -623,7 +702,7 @@ install-binPROGRAMS: install-libLTLIBRARIES
 
 installdirs:
        for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \
-         test -z "$$dir" || $(mkdir_p) "$$dir"; \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
 install: install-am
 install-exec: install-exec-am
@@ -645,6 +724,7 @@ clean-generic:
 
 distclean-generic:
        -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
@@ -667,6 +747,8 @@ dvi-am:
 
 html: html-am
 
+html-am:
+
 info: info-am
 
 info-am:
@@ -674,12 +756,30 @@ info-am:
 install-data-am: install-includeHEADERS install-man \
        install-pkgconfigDATA
 
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
 install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
 
+install-html: install-html-am
+
+install-html-am:
+
 install-info: install-info-am
 
+install-info-am:
+
 install-man: install-man1
 
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
@@ -703,30 +803,34 @@ ps: ps-am
 ps-am:
 
 uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
-       uninstall-info-am uninstall-libLTLIBRARIES uninstall-man \
-       uninstall-pkgconfigDATA
+       uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA
 
 uninstall-man: uninstall-man1
 
+.MAKE: install-am install-strip
+
 .PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
        clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
        clean-libtool ctags dist dist-all dist-bzip2 dist-gzip \
-       dist-shar dist-tarZ dist-zip distcheck distclean \
-       distclean-compile distclean-generic distclean-libtool \
-       distclean-tags distcleancheck distdir distuninstallcheck dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-binPROGRAMS install-data install-data-am install-exec \
-       install-exec-am install-includeHEADERS install-info \
-       install-info-am install-libLTLIBRARIES install-man \
-       install-man1 install-pkgconfigDATA install-strip installcheck \
-       installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-compile \
-       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-       tags uninstall uninstall-am uninstall-binPROGRAMS \
-       uninstall-includeHEADERS uninstall-info-am \
+       dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \
+       distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distcleancheck distdir \
+       distuninstallcheck dvi dvi-am html html-am info info-am \
+       install install-am install-binPROGRAMS install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am \
+       install-includeHEADERS install-info install-info-am \
+       install-libLTLIBRARIES install-man install-man1 install-pdf \
+       install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags uninstall uninstall-am \
+       uninstall-binPROGRAMS uninstall-includeHEADERS \
        uninstall-libLTLIBRARIES uninstall-man uninstall-man1 \
        uninstall-pkgconfigDATA
 
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
index c7a79f700bff7ed8a715f7e213a48f50aec3832d..e0553de2feed29172630320370087b74f1322eb5 100755 (executable)
@@ -1,20 +1,24 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.62 for sqlite 3.7.6.2.
+# Generated by GNU Autoconf 2.65 for sqlite 3.7.7.1.
 #
 # Report bugs to <http://www.sqlite.org>.
 #
+#
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+#
+#
 # This configure script is free software; the Free Software Foundation
 # gives unlimited permission to copy, distribute and modify it.
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
 
 # Be more Bourne compatible
 DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
   # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
@@ -22,23 +26,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
 esac
-
 fi
 
 
-
-
-# PATH needs CR
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
 as_nl='
 '
 export as_nl
@@ -46,7 +42,13 @@ export as_nl
 as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
   as_echo='printf %s\n'
   as_echo_n='printf %s'
 else
@@ -57,7 +59,7 @@ else
     as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
     as_echo_n_body='eval
       arg=$1;
-      case $arg in
+      case $arg in #(
       *"$as_nl"*)
        expr "X$arg" : "X\\(.*\\)$as_nl";
        arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
@@ -80,13 +82,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
   }
 fi
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
-else
-  as_unset=false
-fi
-
 
 # IFS
 # We need space, tab and new line, in precisely that order.  Quoting is
@@ -96,15 +91,15 @@ fi
 IFS=" ""       $as_nl"
 
 # Find who we are.  Look in the path if we contain no directory separator.
-case $0 in
+case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
   *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
 IFS=$as_save_IFS
 
      ;;
@@ -116,12 +111,16 @@ if test "x$as_myself" = x; then
 fi
 if test ! -f "$as_myself"; then
   $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  { (exit 1); exit 1; }
+  exit 1
 fi
 
-# Work around bugs in pre-3.0 UWIN ksh.
-for as_var in ENV MAIL MAILPATH
-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
 done
 PS1='$ '
 PS2='> '
@@ -133,7 +132,249 @@ export LC_ALL
 LANGUAGE=C
 export LANGUAGE
 
-# Required to use basename.
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+       # neutralization value for shells without unset; and this also
+       # works around shells that cannot unset nonexistent variables.
+       BASH_ENV=/dev/null
+       ENV=/dev/null
+       (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+       export CONFIG_SHELL
+       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: http://www.sqlite.org about your system, including any
+$0: error possibly output before this message. Then install
+$0: a modern shell, or manually run the script under such a
+$0: shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
 if expr a : '\(a\)' >/dev/null 2>&1 &&
    test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
@@ -147,8 +388,12 @@ else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
 as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
         X"$0" : 'X\(//\)$' \| \
@@ -168,409 +413,120 @@ $as_echo X/"$0" |
          }
          s/.*/./; q'`
 
-# CDPATH.
-$as_unset CDPATH
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
 
 
-if test "x$CONFIG_SHELL" = x; then
-  if (eval ":") 2>/dev/null; then
-  as_have_required=yes
-else
-  as_have_required=no
-fi
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
-  if test $as_have_required = yes &&    (eval ":
-(as_func_return () {
-  (exit \$1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
 }
 
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
 
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
 fi
-
-if as_func_ret_success; then
-  :
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
 else
-  exitcode=1
-  echo as_func_ret_success failed.
+  as_ln_s='cp -p'
 fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
 
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
 fi
 
-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
-  :
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
 else
-  exitcode=1
-  echo positional parameters were not saved.
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
 fi
+as_executable_p=$as_test_x
 
-test \$exitcode = 0) || { (exit 1); exit 1; }
-
-(
-  as_lineno_1=\$LINENO
-  as_lineno_2=\$LINENO
-  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
-  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
-") 2> /dev/null; then
-  :
-else
-  as_candidate_shells=
-    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  case $as_dir in
-        /*)
-          for as_base in sh bash ksh sh5; do
-            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
-          done;;
-       esac
-done
-IFS=$as_save_IFS
-
-
-      for as_shell in $as_candidate_shells $SHELL; do
-        # Try only shells that exist, to save several forks.
-        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
-               { ("$as_shell") 2> /dev/null <<\_ASEOF
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
-esac
-
-fi
-
-
-:
-_ASEOF
-}; then
-  CONFIG_SHELL=$as_shell
-              as_have_required=yes
-              if { "$as_shell" 2> /dev/null <<\_ASEOF
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
-esac
-
-fi
-
-
-:
-(as_func_return () {
-  (exit $1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
-}
-
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
-
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
-fi
-
-if as_func_ret_success; then
-  :
-else
-  exitcode=1
-  echo as_func_ret_success failed.
-fi
-
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
-fi
-
-if ( set x; as_func_ret_success y && test x = "$1" ); then
-  :
-else
-  exitcode=1
-  echo positional parameters were not saved.
-fi
-
-test $exitcode = 0) || { (exit 1); exit 1; }
-
-(
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
-
-_ASEOF
-}; then
-  break
-fi
-
-fi
-
-      done
-
-      if test "x$CONFIG_SHELL" != x; then
-  for as_var in BASH_ENV ENV
-       do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
-       done
-       export CONFIG_SHELL
-       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
-fi
-
-
-    if test $as_have_required = no; then
-  echo This script requires a shell more modern than all the
-      echo shells that I found on your system.  Please install a
-      echo modern shell, or manually run the script under such a
-      echo shell if you do have one.
-      { (exit 1); exit 1; }
-fi
-
-
-fi
-
-fi
-
-
-
-(eval "as_func_return () {
-  (exit \$1)
-}
-as_func_success () {
-  as_func_return 0
-}
-as_func_failure () {
-  as_func_return 1
-}
-as_func_ret_success () {
-  return 0
-}
-as_func_ret_failure () {
-  return 1
-}
-
-exitcode=0
-if as_func_success; then
-  :
-else
-  exitcode=1
-  echo as_func_success failed.
-fi
-
-if as_func_failure; then
-  exitcode=1
-  echo as_func_failure succeeded.
-fi
-
-if as_func_ret_success; then
-  :
-else
-  exitcode=1
-  echo as_func_ret_success failed.
-fi
-
-if as_func_ret_failure; then
-  exitcode=1
-  echo as_func_ret_failure succeeded.
-fi
-
-if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
-  :
-else
-  exitcode=1
-  echo positional parameters were not saved.
-fi
-
-test \$exitcode = 0") || {
-  echo No shell found that supports shell functions.
-  echo Please tell bug-autoconf@gnu.org about your system,
-  echo including any error possibly output before this message.
-  echo This can help us improve future autoconf versions.
-  echo Configuration will now proceed without shell functions.
-}
-
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line after each line using $LINENO; the second 'sed'
-  # does the real work.  The second script uses 'N' to pair each
-  # line-number line with the line containing $LINENO, and appends
-  # trailing '-' during substitution so that $LINENO is not a special
-  # case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # scripts with optimization help from Paolo Bonzini.  Blame Lee
-  # E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in
--n*)
-  case `echo 'x\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  *)   ECHO_C='\c';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -p'
-  fi
-else
-  as_ln_s='cp -p'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-       test -d "$1/.";
-      else
-       case $1 in
-       -*)set "./$1";;
-       esac;
-       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
-       ???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
 
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
 
@@ -727,7 +683,8 @@ tagnames=${tagnames+${tagnames},}CXX
 
 tagnames=${tagnames+${tagnames},}F77
 
-exec 7<&0 </dev/null 6>&1
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
 
 # Name of the host.
 # hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
@@ -745,14 +702,14 @@ cross_compiling=no
 subdirs=
 MFLAGS=
 MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
 
 # Identity of this package.
 PACKAGE_NAME='sqlite'
 PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.7.6.2'
-PACKAGE_STRING='sqlite 3.7.6.2'
+PACKAGE_VERSION='3.7.7.1'
+PACKAGE_STRING='sqlite 3.7.7.1'
 PACKAGE_BUGREPORT='http://www.sqlite.org'
+PACKAGE_URL=''
 
 ac_unique_file="sqlite3.c"
 # Factoring default headers for most tests.
@@ -791,113 +748,114 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL
-PATH_SEPARATOR
-PACKAGE_NAME
-PACKAGE_TARNAME
-PACKAGE_VERSION
-PACKAGE_STRING
-PACKAGE_BUGREPORT
-exec_prefix
-prefix
-program_transform_name
-bindir
-sbindir
-libexecdir
-datarootdir
-datadir
-sysconfdir
-sharedstatedir
-localstatedir
-includedir
-oldincludedir
-docdir
-infodir
-htmldir
-dvidir
-pdfdir
-psdir
-libdir
-localedir
-mandir
-DEFS
-ECHO_C
-ECHO_N
-ECHO_T
-LIBS
-build_alias
-host_alias
-target_alias
-INSTALL_PROGRAM
-INSTALL_SCRIPT
-INSTALL_DATA
-CYGPATH_W
-PACKAGE
-VERSION
-ACLOCAL
-AUTOCONF
-AUTOMAKE
-AUTOHEADER
-MAKEINFO
-install_sh
-STRIP
-INSTALL_STRIP_PROGRAM
-mkdir_p
-AWK
-SET_MAKE
-am__leading_dot
-AMTAR
-am__tar
-am__untar
-CC
-CFLAGS
-LDFLAGS
-CPPFLAGS
-ac_ct_CC
-EXEEXT
-OBJEXT
-DEPDIR
-am__include
-am__quote
-AMDEP_TRUE
-AMDEP_FALSE
-AMDEPBACKSLASH
-CCDEPMODE
-am__fastdepCC_TRUE
-am__fastdepCC_FALSE
-RANLIB
-build
-build_cpu
-build_vendor
-build_os
-host
-host_cpu
-host_vendor
-host_os
-GREP
-EGREP
-LN_S
-ECHO
-AR
-CPP
-CXX
-CXXFLAGS
-ac_ct_CXX
-CXXDEPMODE
-am__fastdepCXX_TRUE
-am__fastdepCXX_FALSE
-CXXCPP
-F77
-FFLAGS
-ac_ct_F77
-LIBTOOL
-MKDIR_P
-BUILD_CFLAGS
-READLINE_LIBS
-THREADSAFE_FLAGS
-DYNAMIC_EXTENSION_FLAGS
+ac_subst_vars='LTLIBOBJS
 LIBOBJS
-LTLIBOBJS'
+DYNAMIC_EXTENSION_FLAGS
+THREADSAFE_FLAGS
+READLINE_LIBS
+BUILD_CFLAGS
+MKDIR_P
+LIBTOOL
+ac_ct_F77
+FFLAGS
+F77
+CXXCPP
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+CPP
+AR
+ECHO
+LN_S
+EGREP
+GREP
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+RANLIB
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
@@ -1037,8 +995,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1064,8 +1021,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1269,8 +1225,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1286,8 +1241,7 @@ do
     ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
-   { (exit 1); exit 1; }; }
+      as_fn_error "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
     case $ac_user_opts in
@@ -1317,17 +1271,17 @@ do
   | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
     x_libraries=$ac_optarg ;;
 
-  -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; }
+  -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
     ;;
 
   *=*)
     ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
-      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
-   { (exit 1); exit 1; }; }
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+    esac
     eval $ac_envvar=\$ac_optarg
     export $ac_envvar ;;
 
@@ -1344,16 +1298,14 @@ done
 
 if test -n "$ac_prev"; then
   ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error "missing argument to $ac_option"
 fi
 
 if test -n "$ac_unrecognized_opts"; then
   case $enable_option_checking in
     no) ;;
-    fatal) { $as_echo "$as_me: error: Unrecognized options: $ac_unrecognized_opts" >&2
-   { (exit 1); exit 1; }; } ;;
-    *)     $as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2 ;;
+    fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
   esac
 fi
 
@@ -1375,8 +1327,7 @@ do
     [\\/$]* | ?:[\\/]* )  continue;;
     NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
   esac
-  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
 done
 
 # There might be people who depend on the old broken behavior: `$host'
@@ -1406,11 +1357,9 @@ test "$silent" = yes && exec 6>/dev/null
 ac_pwd=`pwd` && test -n "$ac_pwd" &&
 ac_ls_di=`ls -di .` &&
 ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  { $as_echo "$as_me: error: Working directory cannot be determined" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error "working directory cannot be determined"
 test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error "pwd does not report name of working directory"
 
 
 # Find the source files, if location was not specified.
@@ -1449,13 +1398,11 @@ else
 fi
 if test ! -r "$srcdir/$ac_unique_file"; then
   test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
 fi
 ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
 ac_abs_confdir=`(
-       cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
-   { (exit 1); exit 1; }; }
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
        pwd)`
 # When building in place, set srcdir=.
 if test "$ac_abs_confdir" = "$ac_pwd"; then
@@ -1481,7 +1428,7 @@ if test "$ac_init_help" = "long"; then
   # 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 <<_ACEOF
-\`configure' configures sqlite 3.7.6.2 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.7.7.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1536,147 +1483,748 @@ Fine tuning of the installation directories:
   --psdir=DIR             ps documentation [DOCDIR]
 _ACEOF
 
-  cat <<\_ACEOF
+  cat <<\_ACEOF
+
+Program names:
+  --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
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of sqlite 3.7.7.1:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-largefile     omit support for large files
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-readline       use readline in shell tool (yes, no) [default=yes]
+  --enable-threadsafe     build a thread-safe library [default=yes]
+  --enable-dynamic-extensions
+                          support loadable extensions [default=yes]
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-pic              try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-tags[=TAGS]      include additional configurations [automatic]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CXXCPP      C++ preprocessor
+  F77         Fortran 77 compiler command
+  FFLAGS      Fortran 77 compiler flags
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <http://www.sqlite.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+sqlite configure 3.7.7.1
+generated by GNU Autoconf 2.65
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to http://www.sqlite.org ##
+## ------------------------------------ ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* 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_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
 
-Program names:
-  --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
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_cxx_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-System types:
-  --build=BUILD     configure for building on BUILD [guessed]
-  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
-_ACEOF
+       ac_retval=1
 fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-if test -n "$ac_init_help"; then
-  case $ac_init_help in
-     short | recursive ) echo "Configuration of sqlite 3.7.6.2:";;
-   esac
-  cat <<\_ACEOF
+} # ac_fn_cxx_try_compile
 
-Optional Features:
-  --disable-option-checking  ignore unrecognized --enable/--with options
-  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
-  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --disable-largefile     omit support for large files
-  --disable-dependency-tracking  speeds up one-time build
-  --enable-dependency-tracking   do not reject slow dependency extractors
-  --enable-shared[=PKGS]  build shared libraries [default=yes]
-  --enable-static[=PKGS]  build static libraries [default=yes]
-  --enable-fast-install[=PKGS]
-                          optimize for fast installation [default=yes]
-  --disable-libtool-lock  avoid locking (might break parallel builds)
-  --enable-readline       use readline in shell tool (yes, no) [default=yes]
-  --enable-threadsafe     build a thread-safe library [default=yes]
-  --enable-dynamic-extensions
-                          support loadable extensions [default=yes]
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } >/dev/null && {
+        test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-Optional Packages:
-  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
-  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
-  --with-pic              try to use only PIC/non-PIC objects [default=use
-                          both]
-  --with-tags[=TAGS]      include additional configurations [automatic]
+    ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-Some influential environment variables:
-  CC          C compiler command
-  CFLAGS      C compiler flags
-  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
-              nonstandard directory <lib dir>
-  LIBS        libraries to pass to the linker, e.g. -l<library>
-  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
-              you have headers in a nonstandard directory <include dir>
-  CPP         C preprocessor
-  CXX         C++ compiler command
-  CXXFLAGS    C++ compiler flags
-  CXXCPP      C++ preprocessor
-  F77         Fortran 77 compiler command
-  FFLAGS      Fortran 77 compiler flags
+} # ac_fn_cxx_try_cpp
 
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_cxx_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-Report bugs to <http://www.sqlite.org>.
-_ACEOF
-ac_status=$?
+       ac_retval=1
 fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-if test "$ac_init_help" = "recursive"; then
-  # If there are subdirs, report their specific --help.
-  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
-    test -d "$ac_dir" ||
-      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
-      continue
-    ac_builddir=.
+} # ac_fn_cxx_try_link
 
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
+# ac_fn_f77_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_f77_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
 esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_f77_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+       ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_f77_try_compile
+
+# ac_fn_f77_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_f77_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
 esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_f77_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-    cd "$ac_dir" || { ac_status=$?; continue; }
-    # Check for guested configure.
-    if test -f "$ac_srcdir/configure.gnu"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
-    elif test -f "$ac_srcdir/configure"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure" --help=recursive
-    else
-      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
-    fi || ac_status=$?
-    cd "$ac_pwd" || { ac_status=$?; break; }
-  done
+       ac_retval=1
 fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
 
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
-  cat <<\_ACEOF
-sqlite configure 3.7.6.2
-generated by GNU Autoconf 2.62
+} # ac_fn_f77_try_link
 
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
+# ac_fn_c_check_decl LINENO SYMBOL VAR
+# ------------------------------------
+# Tests whether SYMBOL is declared, setting cache variable VAR accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5
+$as_echo_n "checking whether $2 is declared... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $2
+  (void) $2;
+#endif
+
+  ;
+  return 0;
+}
 _ACEOF
-  exit
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_decl
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sqlite $as_me 3.7.6.2, which was
-generated by GNU Autoconf 2.62.  Invocation command line was
+It was created by sqlite $as_me 3.7.7.1, which was
+generated by GNU Autoconf 2.65.  Invocation command line was
 
   $ $0 $@
 
@@ -1712,8 +2260,8 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  $as_echo "PATH: $as_dir"
-done
+    $as_echo "PATH: $as_dir"
+  done
 IFS=$as_save_IFS
 
 } >&5
@@ -1750,9 +2298,9 @@ do
       ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
     esac
     case $ac_pass in
-    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
     2)
-      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      as_fn_append ac_configure_args1 " '$ac_arg'"
       if test $ac_must_keep_next = true; then
        ac_must_keep_next=false # Got value, back to normal.
       else
@@ -1768,13 +2316,13 @@ do
          -* ) ac_must_keep_next=true ;;
        esac
       fi
-      ac_configure_args="$ac_configure_args '$ac_arg'"
+      as_fn_append ac_configure_args " '$ac_arg'"
       ;;
     esac
   done
 done
-$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
-$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
 
 # When interrupted or exit'd, cleanup temporary files, and complete
 # config.log.  We remove comments because anyway the quotes in there
@@ -1799,13 +2347,13 @@ _ASBOX
     case $ac_val in #(
     *${as_nl}*)
       case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
-$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
       esac
       case $ac_var in #(
       _ | IFS | as_nl) ;; #(
       BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) $as_unset $ac_var ;;
+      *) { eval $ac_var=; unset $ac_var;} ;;
       esac ;;
     esac
   done
@@ -1877,39 +2425,41 @@ _ASBOX
     exit $exit_status
 ' 0
 for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
 done
 ac_signal=0
 
 # confdefs.h avoids OS command line length limits that DEFS can exceed.
 rm -f -r conftest* confdefs.h
 
+$as_echo "/* confdefs.h */" > confdefs.h
+
 # Predefined preprocessor variables.
 
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_NAME "$PACKAGE_NAME"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_TARNAME "$PACKAGE_TARNAME"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_VERSION "$PACKAGE_VERSION"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_STRING "$PACKAGE_STRING"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
 _ACEOF
 
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
 
 # Let the site file select an alternate cache file if it wants to.
 # Prefer an explicitly selected file to automatically selected ones.
@@ -1927,8 +2477,8 @@ fi
 for ac_site_file in "$ac_site_file1" "$ac_site_file2"
 do
   test "x$ac_site_file" = xNONE && continue
-  if test -r "$ac_site_file"; then
-    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
 $as_echo "$as_me: loading site script $ac_site_file" >&6;}
     sed 's/^/| /' "$ac_site_file" >&5
     . "$ac_site_file"
@@ -1936,10 +2486,10 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;}
 done
 
 if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special
-  # files actually), so we avoid doing that.
-  if test -f "$cache_file"; then
-    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
 $as_echo "$as_me: loading cache $cache_file" >&6;}
     case $cache_file in
       [\\/]* | ?:[\\/]* ) . "$cache_file";;
@@ -1947,7 +2497,7 @@ $as_echo "$as_me: loading cache $cache_file" >&6;}
     esac
   fi
 else
-  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
 $as_echo "$as_me: creating cache $cache_file" >&6;}
   >$cache_file
 fi
@@ -1962,11 +2512,11 @@ for ac_var in $ac_precious_vars; do
   eval ac_new_val=\$ac_env_${ac_var}_value
   case $ac_old_set,$ac_new_set in
     set,)
-      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
       ac_cache_corrupted=: ;;
     ,set)
-      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
       ac_cache_corrupted=: ;;
     ,);;
@@ -1976,17 +2526,17 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
        ac_old_val_w=`echo x $ac_old_val`
        ac_new_val_w=`echo x $ac_new_val`
        if test "$ac_old_val_w" != "$ac_new_val_w"; then
-         { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
          ac_cache_corrupted=:
        else
-         { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
          eval $ac_var=\$ac_old_val
        fi
-       { $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
 $as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
-       { $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
 $as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
       fi;;
   esac
@@ -1998,41 +2548,20 @@ $as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
     esac
     case " $ac_configure_args " in
       *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
     esac
   fi
 done
 if $ac_cache_corrupted; then
-  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
-$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
 fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -2046,25 +2575,17 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 # Use automake.
 am__api_version="1.9"
 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
-  elif test -f "$ac_dir/shtool"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/shtool install -c"
-    break
-  fi
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  for ac_t in install-sh install.sh shtool; do
+    if test -f "$ac_dir/$ac_t"; then
+      ac_aux_dir=$ac_dir
+      ac_install_sh="$ac_aux_dir/$ac_t -c"
+      break 2
+    fi
+  done
 done
 if test -z "$ac_aux_dir"; then
-  { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
-$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
 fi
 
 # These three variables are undocumented and unsupported,
@@ -2090,10 +2611,10 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 # OS/2's system install, which has a completely different semantic
 # ./install, which can be erroneously created by make from ./install.sh.
 # Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
 $as_echo_n "checking for a BSD-compatible install... " >&6; }
 if test -z "$INSTALL"; then
-if test "${ac_cv_path_install+set}" = set; then
+if test "${ac_cv_path_install+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -2101,11 +2622,11 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in
-  ./ | .// | /cC/* | \
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
   /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
-  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
   /usr/ucb/* ) ;;
   *)
     # OSF1 and SCO ODT 3.0 have their own names for install.
@@ -2142,7 +2663,7 @@ case $as_dir/ in
     ;;
 esac
 
-done
+  done
 IFS=$as_save_IFS
 
 rm -rf conftest.one conftest.two conftest.dir
@@ -2158,7 +2679,7 @@ fi
     INSTALL=$ac_install_sh
   fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
 $as_echo "$INSTALL" >&6; }
 
 # Use test -z because SunOS4 sh mishandles braces in ${var-val}.
@@ -2169,7 +2690,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
 
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
-{ $as_echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
 $as_echo_n "checking whether build environment is sane... " >&6; }
 # Just in case
 sleep 1
@@ -2193,11 +2714,8 @@ if (
       # if, for instance, CONFIG_SHELL is bash and it inherits a
       # broken ls alias from the environment.  This has actually
       # happened.  Such a system could not be considered "sane".
-      { { $as_echo "$as_me:$LINENO: error: ls -t appears to fail.  Make sure there is not a broken
-alias in your environment" >&5
-$as_echo "$as_me: error: ls -t appears to fail.  Make sure there is not a broken
-alias in your environment" >&2;}
-   { (exit 1); exit 1; }; }
+      as_fn_error "ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" "$LINENO" 5
    fi
 
    test "$2" = conftest.file
@@ -2206,13 +2724,10 @@ then
    # Ok.
    :
 else
-   { { $as_echo "$as_me:$LINENO: error: newly created file is older than distributed files!
-Check your system clock" >&5
-$as_echo "$as_me: error: newly created file is older than distributed files!
-Check your system clock" >&2;}
-   { (exit 1); exit 1; }; }
+   as_fn_error "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
 fi
-{ $as_echo "$as_me:$LINENO: result: yes" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 test "$program_prefix" != NONE &&
   program_transform_name="s&^&$program_prefix&;$program_transform_name"
@@ -2233,7 +2748,7 @@ if eval "$MISSING --run true"; then
   am_missing_run="$MISSING --run "
 else
   am_missing_run=
-  { $as_echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
 fi
 
@@ -2274,9 +2789,9 @@ for ac_prog in gawk mawk nawk awk
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_AWK+set}" = set; then
+if test "${ac_cv_prog_AWK+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$AWK"; then
@@ -2287,24 +2802,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_AWK="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 AWK=$ac_cv_prog_AWK
 if test -n "$AWK"; then
-  { $as_echo "$as_me:$LINENO: result: $AWK" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
 $as_echo "$AWK" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2312,11 +2827,11 @@ fi
   test -n "$AWK" && break
 done
 
-{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
 set x ${MAKE-make}
 ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
   cat >conftest.make <<\_ACEOF
@@ -2334,11 +2849,11 @@ esac
 rm -f conftest.make
 fi
 if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
-  { $as_echo "$as_me:$LINENO: result: yes" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
   SET_MAKE=
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
   SET_MAKE="MAKE=${MAKE-make}"
 fi
@@ -2355,9 +2870,7 @@ rmdir .tst 2>/dev/null
 # test to see if srcdir already configured
 if test "`cd $srcdir && pwd`" != "`pwd`" &&
    test -f $srcdir/config.status; then
-  { { $as_echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
-$as_echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
 fi
 
 # test whether we have cygpath
@@ -2372,7 +2885,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='sqlite'
- VERSION='3.7.6.2'
+ VERSION='3.7.7.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2410,9 +2923,9 @@ if test "$cross_compiling" != no; then
   if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
 set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_STRIP+set}" = set; then
+if test "${ac_cv_prog_STRIP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$STRIP"; then
@@ -2423,24 +2936,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 STRIP=$ac_cv_prog_STRIP
 if test -n "$STRIP"; then
-  { $as_echo "$as_me:$LINENO: result: $STRIP" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
 $as_echo "$STRIP" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2450,9 +2963,9 @@ if test -z "$ac_cv_prog_STRIP"; then
   ac_ct_STRIP=$STRIP
   # Extract the first word of "strip", so it can be a program name with args.
 set dummy strip; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_STRIP"; then
@@ -2463,24 +2976,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_STRIP="strip"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
 if test -n "$ac_ct_STRIP"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
 $as_echo "$ac_ct_STRIP" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2489,12 +3002,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     STRIP=$ac_ct_STRIP
@@ -2531,7 +3040,7 @@ am__doit:
 .PHONY: am__doit
 END
 # If we don't find an include directive, just comment out the code.
-{ $as_echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
 $as_echo_n "checking for style of include used by $am_make... " >&6; }
 am__include="#"
 am__quote=
@@ -2559,12 +3068,12 @@ if test "$am__include" = "#"; then
 fi
 
 
-{ $as_echo "$as_me:$LINENO: result: $_am_result" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
 $as_echo "$_am_result" >&6; }
 rm -f confinc confmf
 
 # Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then
+if test "${enable_dependency_tracking+set}" = set; then :
   enableval=$enable_dependency_tracking;
 fi
 
@@ -2592,9 +3101,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -2605,24 +3114,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2632,9 +3141,9 @@ if test -z "$ac_cv_prog_CC"; then
   ac_ct_CC=$CC
   # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
@@ -2645,24 +3154,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
 $as_echo "$ac_ct_CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2671,12 +3180,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     CC=$ac_ct_CC
@@ -2689,9 +3194,9 @@ if test -z "$CC"; then
           if test -n "$ac_tool_prefix"; then
     # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -2702,24 +3207,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2729,9 +3234,9 @@ 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
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -2743,18 +3248,18 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
      fi
     ac_cv_prog_CC="cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 if test $ac_prog_rejected = yes; then
@@ -2773,10 +3278,10 @@ fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2788,9 +3293,9 @@ if test -z "$CC"; then
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -2801,24 +3306,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2832,9 +3337,9 @@ if test -z "$CC"; then
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
@@ -2845,24 +3350,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
 $as_echo "$ac_ct_CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -2875,12 +3380,8 @@ done
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     CC=$ac_ct_CC
@@ -2890,55 +3391,37 @@ fi
 fi
 
 
-test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
 
 # Provide some information about the compiler.
-$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
 set X $ac_compile
 ac_compiler=$2
-{ (ac_try="$ac_compiler --version >&5"
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -2954,8 +3437,8 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
 # Try to create an executable without -o first, disregard a.out.
 # It will help us diagnose broken compilers, and finding out an intuition
 # of exeext.
-{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
 ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
 
 # The possible output files:
@@ -2971,17 +3454,17 @@ do
 done
 rm -f $ac_rmfiles
 
-if { (ac_try="$ac_link_default"
+if { ac_try="$ac_link_default"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
   (eval "$ac_link_default") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
   # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
 # So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
 # in a Makefile.  We should not override ac_cv_exeext if it was cached,
@@ -2998,7 +3481,7 @@ do
        # certainly right.
        break;;
     *.* )
-        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
        then :; else
           ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
        fi
@@ -3017,80 +3500,42 @@ test "$ac_cv_exeext" = no && ac_cv_exeext=
 else
   ac_file=''
 fi
-
-{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-if test -z "$ac_file"; then
-  $as_echo "$as_me: failed program was:" >&5
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: C compiler cannot create executables
-See \`config.log' for more details." >&2;}
-   { (exit 77); exit 77; }; }
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 fi
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
 ac_exeext=$ac_cv_exeext
 
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
-# If not cross compiling, check that we can run a simple program.
-if test "$cross_compiling" != yes; then
-  if { ac_try='./$ac_file'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-       cross_compiling=yes
-    else
-       { { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
-    fi
-  fi
-fi
-{ $as_echo "$as_me:$LINENO: result: yes" >&5
-$as_echo "yes" >&6; }
-
 rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
 ac_clean_files=$ac_clean_files_save
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
 $as_echo_n "checking for suffix of executables... " >&6; }
-if { (ac_try="$ac_link"
+if { ac_try="$ac_link"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
   (eval "$ac_link") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
   # If both `conftest.exe' and `conftest' are `present' (well, observable)
 # catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
 # work properly (i.e., refer to `conftest.exe'), while it won't with
@@ -3105,30 +3550,83 @@ for ac_file in conftest.exe conftest conftest.*; do
   esac
 done
 else
-  { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
 fi
-
-rm -f conftest$ac_cv_exeext
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
 $as_echo "$ac_cv_exeext" >&6; }
 
 rm -f conftest.$ac_ext
 EXEEXT=$ac_cv_exeext
 ac_exeext=$EXEEXT
-{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
 $as_echo_n "checking for suffix of object files... " >&6; }
-if test "${ac_cv_objext+set}" = set; then
+if test "${ac_cv_objext+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -3140,17 +3638,17 @@ main ()
 }
 _ACEOF
 rm -f conftest.o conftest.obj
-if { (ac_try="$ac_compile"
+if { ac_try="$ac_compile"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
   (eval "$ac_compile") 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
   for ac_file in conftest.o conftest.obj conftest.*; do
   test -f "$ac_file" || continue;
   case $ac_file in
@@ -3163,29 +3661,23 @@ else
   $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
 fi
-
 rm -f conftest.$ac_cv_objext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
 $as_echo "$ac_cv_objext" >&6; }
 OBJEXT=$ac_cv_objext
 ac_objext=$OBJEXT
-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if test "${ac_cv_c_compiler_gnu+set}" = set; then
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -3199,37 +3691,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_c_compiler_gnu=$ac_compiler_gnu
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
 $as_echo "$ac_cv_c_compiler_gnu" >&6; }
 if test $ac_compiler_gnu = yes; then
   GCC=yes
@@ -3238,20 +3709,16 @@ else
 fi
 ac_test_CFLAGS=${CFLAGS+set}
 ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
 $as_echo_n "checking whether $CC accepts -g... " >&6; }
-if test "${ac_cv_prog_cc_g+set}" = set; then
+if test "${ac_cv_prog_cc_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_save_c_werror_flag=$ac_c_werror_flag
    ac_c_werror_flag=yes
    ac_cv_prog_cc_g=no
    CFLAGS="-g"
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -3262,35 +3729,11 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_g=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       CFLAGS=""
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -3301,36 +3744,12 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_compile "$LINENO"; then :
 
-       ac_c_werror_flag=$ac_save_c_werror_flag
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
         CFLAGS="-g"
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -3341,42 +3760,17 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_g=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    ac_c_werror_flag=$ac_save_c_werror_flag
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
 $as_echo "$ac_cv_prog_cc_g" >&6; }
 if test "$ac_test_CFLAGS" = set; then
   CFLAGS=$ac_save_CFLAGS
@@ -3393,18 +3787,14 @@ else
     CFLAGS=
   fi
 fi
-{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if test "${ac_cv_prog_cc_c89+set}" = set; then
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_cv_prog_cc_c89=no
 ac_save_CC=$CC
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
@@ -3461,32 +3851,9 @@ for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
        -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
 do
   CC="$ac_save_CC $ac_arg"
-  rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+  if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_c89=$ac_arg
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext
   test "x$ac_cv_prog_cc_c89" != "xno" && break
 done
@@ -3497,17 +3864,19 @@ fi
 # AC_CACHE_VAL
 case "x$ac_cv_prog_cc_c89" in
   x)
-    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
 $as_echo "none needed" >&6; } ;;
   xno)
-    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
 $as_echo "unsupported" >&6; } ;;
   *)
     CC="$CC $ac_cv_prog_cc_c89"
-    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
 esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
 
+fi
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -3517,9 +3886,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 depcc="$CC"   am_compiler_list=
 
-{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
 $as_echo_n "checking dependency style of $depcc... " >&6; }
-if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
@@ -3607,7 +3976,7 @@ else
 fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
 CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
 
@@ -3626,15 +3995,15 @@ fi
 
 
 # Check whether --enable-largefile was given.
-if test "${enable_largefile+set}" = set; then
+if test "${enable_largefile+set}" = set; then :
   enableval=$enable_largefile;
 fi
 
 if test "$enable_largefile" != no; then
 
-  { $as_echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
 $as_echo_n "checking for special C compiler options needed for large files... " >&6; }
-if test "${ac_cv_sys_largefile_CC+set}" = set; then
+if test "${ac_cv_sys_largefile_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_cv_sys_largefile_CC=no
@@ -3643,11 +4012,7 @@ else
        while :; do
         # IRIX 6.2 and later do not support large files by default,
         # so use the C compiler's -n32 option if that helps.
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <sys/types.h>
  /* Check that off_t can represent 2**63 - 1 correctly.
@@ -3666,60 +4031,14 @@ main ()
   return 0;
 }
 _ACEOF
-        rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+        if ac_fn_c_try_compile "$LINENO"; then :
   break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext
         CC="$CC -n32"
-        rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+        if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_sys_largefile_CC=' -n32'; break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext
         break
        done
@@ -3727,23 +4046,19 @@ rm -f core conftest.err conftest.$ac_objext
        rm -f conftest.$ac_ext
     fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
 $as_echo "$ac_cv_sys_largefile_CC" >&6; }
   if test "$ac_cv_sys_largefile_CC" != no; then
     CC=$CC$ac_cv_sys_largefile_CC
   fi
 
-  { $as_echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if test "${ac_cv_sys_file_offset_bits+set}" = set; then
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   while :; do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <sys/types.h>
  /* Check that off_t can represent 2**63 - 1 correctly.
@@ -3762,38 +4077,11 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_sys_file_offset_bits=no; break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #define _FILE_OFFSET_BITS 64
 #include <sys/types.h>
@@ -3802,49 +4090,26 @@ cat >>conftest.$ac_ext <<_ACEOF
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
 #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
-  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
-                      && LARGE_OFF_T % 2147483647 == 1)
-                     ? 1 : -1];
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_sys_file_offset_bits=64; break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
 
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_cv_sys_file_offset_bits=unknown
   break
 done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
 $as_echo "$ac_cv_sys_file_offset_bits" >&6; }
 case $ac_cv_sys_file_offset_bits in #(
   no | unknown) ;;
@@ -3856,17 +4121,13 @@ _ACEOF
 esac
 rm -rf conftest*
   if test $ac_cv_sys_file_offset_bits = unknown; then
-    { $as_echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
-if test "${ac_cv_sys_large_files+set}" = set; then
+if test "${ac_cv_sys_large_files+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   while :; do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <sys/types.h>
  /* Check that off_t can represent 2**63 - 1 correctly.
@@ -3885,38 +4146,11 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_sys_large_files=no; break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #define _LARGE_FILES 1
 #include <sys/types.h>
@@ -3936,38 +4170,15 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_sys_large_files=1; break
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
   ac_cv_sys_large_files=unknown
   break
 done
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
 $as_echo "$ac_cv_sys_large_files" >&6; }
 case $ac_cv_sys_large_files in #(
   no | unknown) ;;
@@ -3991,9 +4202,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -4004,24 +4215,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4031,9 +4242,9 @@ if test -z "$ac_cv_prog_CC"; then
   ac_ct_CC=$CC
   # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
@@ -4044,24 +4255,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="gcc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
 $as_echo "$ac_ct_CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4070,12 +4281,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     CC=$ac_ct_CC
@@ -4088,9 +4295,9 @@ if test -z "$CC"; then
           if test -n "$ac_tool_prefix"; then
     # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -4101,24 +4308,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4128,9 +4335,9 @@ 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
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -4142,18 +4349,18 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
      fi
     ac_cv_prog_CC="cc"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 if test $ac_prog_rejected = yes; then
@@ -4172,10 +4379,10 @@ fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4187,9 +4394,9 @@ if test -z "$CC"; then
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CC+set}" = set; then
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
@@ -4200,24 +4407,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
 $as_echo "$CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4231,9 +4438,9 @@ if test -z "$CC"; then
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
@@ -4244,24 +4451,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
 $as_echo "$ac_ct_CC" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4274,12 +4481,8 @@ done
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     CC=$ac_ct_CC
@@ -4289,60 +4492,42 @@ fi
 fi
 
 
-test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
 
 # Provide some information about the compiler.
-$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
 set X $ac_compile
 ac_compiler=$2
-{ (ac_try="$ac_compiler --version >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if test "${ac_cv_c_compiler_gnu+set}" = set; then
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -4356,37 +4541,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_c_compiler_gnu=$ac_compiler_gnu
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
 $as_echo "$ac_cv_c_compiler_gnu" >&6; }
 if test $ac_compiler_gnu = yes; then
   GCC=yes
@@ -4395,20 +4559,16 @@ else
 fi
 ac_test_CFLAGS=${CFLAGS+set}
 ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
 $as_echo_n "checking whether $CC accepts -g... " >&6; }
-if test "${ac_cv_prog_cc_g+set}" = set; then
+if test "${ac_cv_prog_cc_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_save_c_werror_flag=$ac_c_werror_flag
    ac_c_werror_flag=yes
    ac_cv_prog_cc_g=no
    CFLAGS="-g"
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -4419,35 +4579,11 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_g=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       CFLAGS=""
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -4458,36 +4594,12 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_compile "$LINENO"; then :
 
-       ac_c_werror_flag=$ac_save_c_werror_flag
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
         CFLAGS="-g"
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -4498,42 +4610,17 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_g=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    ac_c_werror_flag=$ac_save_c_werror_flag
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
 $as_echo "$ac_cv_prog_cc_g" >&6; }
 if test "$ac_test_CFLAGS" = set; then
   CFLAGS=$ac_save_CFLAGS
@@ -4550,18 +4637,14 @@ else
     CFLAGS=
   fi
 fi
-{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if test "${ac_cv_prog_cc_c89+set}" = set; then
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_cv_prog_cc_c89=no
 ac_save_CC=$CC
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
@@ -4618,32 +4701,9 @@ for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
        -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
 do
   CC="$ac_save_CC $ac_arg"
-  rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+  if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_c89=$ac_arg
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext
   test "x$ac_cv_prog_cc_c89" != "xno" && break
 done
@@ -4654,17 +4714,19 @@ fi
 # AC_CACHE_VAL
 case "x$ac_cv_prog_cc_c89" in
   x)
-    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
 $as_echo "none needed" >&6; } ;;
   xno)
-    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
 $as_echo "unsupported" >&6; } ;;
   *)
     CC="$CC $ac_cv_prog_cc_c89"
-    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
 esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
 
+fi
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -4674,9 +4736,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 depcc="$CC"   am_compiler_list=
 
-{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
 $as_echo_n "checking dependency style of $depcc... " >&6; }
-if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
@@ -4764,7 +4826,7 @@ else
 fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
 CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
 
@@ -4784,9 +4846,9 @@ fi
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_RANLIB+set}" = set; then
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$RANLIB"; then
@@ -4797,24 +4859,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 RANLIB=$ac_cv_prog_RANLIB
 if test -n "$RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
 $as_echo "$RANLIB" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4824,9 +4886,9 @@ if test -z "$ac_cv_prog_RANLIB"; then
   ac_ct_RANLIB=$RANLIB
   # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_RANLIB"; then
@@ -4837,24 +4899,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
 if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
 $as_echo "$ac_ct_RANLIB" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -4863,12 +4925,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     RANLIB=$ac_ct_RANLIB
@@ -4878,7 +4936,7 @@ else
 fi
 
 # Check whether --enable-shared was given.
-if test "${enable_shared+set}" = set; then
+if test "${enable_shared+set}" = set; then :
   enableval=$enable_shared; p=${PACKAGE-default}
     case $enableval in
     yes) enable_shared=yes ;;
@@ -4902,7 +4960,7 @@ fi
 
 
 # Check whether --enable-static was given.
-if test "${enable_static+set}" = set; then
+if test "${enable_static+set}" = set; then :
   enableval=$enable_static; p=${PACKAGE-default}
     case $enableval in
     yes) enable_static=yes ;;
@@ -4926,7 +4984,7 @@ fi
 
 
 # Check whether --enable-fast-install was given.
-if test "${enable_fast_install+set}" = set; then
+if test "${enable_fast_install+set}" = set; then :
   enableval=$enable_fast_install; p=${PACKAGE-default}
     case $enableval in
     yes) enable_fast_install=yes ;;
@@ -4951,35 +5009,27 @@ fi
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
-$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
 
-{ $as_echo "$as_me:$LINENO: checking build system type" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
 $as_echo_n "checking build system type... " >&6; }
-if test "${ac_cv_build+set}" = set; then
+if test "${ac_cv_build+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_build_alias=$build_alias
 test "x$ac_build_alias" = x &&
   ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
 test "x$ac_build_alias" = x &&
-  { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
-$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
 $as_echo "$ac_cv_build" >&6; }
 case $ac_cv_build in
 *-*-*) ;;
-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
-$as_echo "$as_me: error: invalid value of canonical build" >&2;}
-   { (exit 1); exit 1; }; };;
+*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
 esac
 build=$ac_cv_build
 ac_save_IFS=$IFS; IFS='-'
@@ -4995,28 +5045,24 @@ IFS=$ac_save_IFS
 case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
 
 
-{ $as_echo "$as_me:$LINENO: checking host system type" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
 $as_echo_n "checking host system type... " >&6; }
-if test "${ac_cv_host+set}" = set; then
+if test "${ac_cv_host+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test "x$host_alias" = x; then
   ac_cv_host=$ac_cv_build
 else
   ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
-$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
 fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
 $as_echo "$ac_cv_host" >&6; }
 case $ac_cv_host in
 *-*-*) ;;
-*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
-$as_echo "$as_me: error: invalid value of canonical host" >&2;}
-   { (exit 1); exit 1; }; };;
+*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
 esac
 host=$ac_cv_host
 ac_save_IFS=$IFS; IFS='-'
@@ -5032,9 +5078,9 @@ IFS=$ac_save_IFS
 case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
 
-{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
 $as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if test "${lt_cv_path_SED+set}" = set; then
+if test "${lt_cv_path_SED+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   # Loop through the user's path and test for sed and gsed.
@@ -5086,12 +5132,12 @@ done
 fi
 
 SED=$lt_cv_path_SED
-{ $as_echo "$as_me:$LINENO: result: $SED" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5
 $as_echo "$SED" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
 $as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if test "${ac_cv_path_GREP+set}" = set; then
+if test "${ac_cv_path_GREP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$GREP"; then
@@ -5102,7 +5148,7 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_prog in grep ggrep; do
+    for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
       { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
@@ -5122,7 +5168,7 @@ case `"$ac_path_GREP" --version 2>&1` in
     $as_echo 'GREP' >> "conftest.nl"
     "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
     diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    ac_count=`expr $ac_count + 1`
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
     if test $ac_count -gt ${ac_path_GREP_max-0}; then
       # Best one so far, save it but keep looking for a better one
       ac_cv_path_GREP="$ac_path_GREP"
@@ -5137,26 +5183,24 @@ esac
       $ac_path_GREP_found && break 3
     done
   done
-done
+  done
 IFS=$as_save_IFS
   if test -z "$ac_cv_path_GREP"; then
-    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
-$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
   fi
 else
   ac_cv_path_GREP=$GREP
 fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
 $as_echo "$ac_cv_path_GREP" >&6; }
  GREP="$ac_cv_path_GREP"
 
 
-{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
 $as_echo_n "checking for egrep... " >&6; }
-if test "${ac_cv_path_EGREP+set}" = set; then
+if test "${ac_cv_path_EGREP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
@@ -5170,7 +5214,7 @@ for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_prog in egrep; do
+    for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
       { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
@@ -5190,7 +5234,7 @@ case `"$ac_path_EGREP" --version 2>&1` in
     $as_echo 'EGREP' >> "conftest.nl"
     "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
     diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    ac_count=`expr $ac_count + 1`
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
     if test $ac_count -gt ${ac_path_EGREP_max-0}; then
       # Best one so far, save it but keep looking for a better one
       ac_cv_path_EGREP="$ac_path_EGREP"
@@ -5205,12 +5249,10 @@ esac
       $ac_path_EGREP_found && break 3
     done
   done
-done
+  done
 IFS=$as_save_IFS
   if test -z "$ac_cv_path_EGREP"; then
-    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
-$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
   fi
 else
   ac_cv_path_EGREP=$EGREP
@@ -5218,14 +5260,14 @@ fi
 
    fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
 $as_echo "$ac_cv_path_EGREP" >&6; }
  EGREP="$ac_cv_path_EGREP"
 
 
 
 # Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then
+if test "${with_gnu_ld+set}" = set; then :
   withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
 else
   with_gnu_ld=no
@@ -5234,7 +5276,7 @@ fi
 ac_prog=ld
 if test "$GCC" = yes; then
   # Check if gcc -print-prog-name=ld gives a path.
-  { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
 $as_echo_n "checking for ld used by $CC... " >&6; }
   case $host in
   *-*-mingw*)
@@ -5264,13 +5306,13 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
     ;;
   esac
 elif test "$with_gnu_ld" = yes; then
-  { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
 $as_echo_n "checking for GNU ld... " >&6; }
 else
-  { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
 $as_echo_n "checking for non-GNU ld... " >&6; }
 fi
-if test "${lt_cv_path_LD+set}" = set; then
+if test "${lt_cv_path_LD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$LD"; then
@@ -5301,18 +5343,16 @@ fi
 
 LD="$lt_cv_path_LD"
 if test -n "$LD"; then
-  { $as_echo "$as_me:$LINENO: result: $LD" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
 $as_echo "$LD" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
-test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
-$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
-   { (exit 1); exit 1; }; }
-{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if test "${lt_cv_prog_gnu_ld+set}" = set; then
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   # I'd rather use --version here, but apparently some GNU lds only accept -v.
@@ -5325,19 +5365,19 @@ case `$LD -v 2>&1 </dev/null` in
   ;;
 esac
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
 $as_echo "$lt_cv_prog_gnu_ld" >&6; }
 with_gnu_ld=$lt_cv_prog_gnu_ld
 
 
-{ $as_echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
 $as_echo_n "checking for $LD option to reload object files... " >&6; }
-if test "${lt_cv_ld_reload_flag+set}" = set; then
+if test "${lt_cv_ld_reload_flag+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_ld_reload_flag='-r'
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
 $as_echo "$lt_cv_ld_reload_flag" >&6; }
 reload_flag=$lt_cv_ld_reload_flag
 case $reload_flag in
@@ -5355,9 +5395,9 @@ case $host_os in
     ;;
 esac
 
-{ $as_echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD-compatible nm" >&5
 $as_echo_n "checking for BSD-compatible nm... " >&6; }
-if test "${lt_cv_path_NM+set}" = set; then
+if test "${lt_cv_path_NM+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$NM"; then
@@ -5404,24 +5444,24 @@ else
   test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm
 fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
 $as_echo "$lt_cv_path_NM" >&6; }
 NM="$lt_cv_path_NM"
 
-{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
 $as_echo_n "checking whether ln -s works... " >&6; }
 LN_S=$as_ln_s
 if test "$LN_S" = "ln -s"; then
-  { $as_echo "$as_me:$LINENO: result: yes" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
 $as_echo "no, using $LN_S" >&6; }
 fi
 
-{ $as_echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognise dependent libraries" >&5
 $as_echo_n "checking how to recognise dependent libraries... " >&6; }
-if test "${lt_cv_deplibs_check_method+set}" = set; then
+if test "${lt_cv_deplibs_check_method+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_file_magic_cmd='$MAGIC_CMD'
@@ -5595,7 +5635,7 @@ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
 esac
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
 $as_echo "$lt_cv_deplibs_check_method" >&6; }
 file_magic_cmd=$lt_cv_file_magic_cmd
 deplibs_check_method=$lt_cv_deplibs_check_method
@@ -5614,7 +5654,7 @@ LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
 compiler=$CC
 
 # Check whether --enable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then
+if test "${enable_libtool_lock+set}" = set; then :
   enableval=$enable_libtool_lock;
 fi
 
@@ -5626,11 +5666,11 @@ case $host in
 ia64-*-hpux*)
   # Find out which ABI we are using.
   echo 'int i;' > conftest.$ac_ext
-  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
     case `/usr/bin/file conftest.$ac_objext` in
     *ELF-32*)
       HPUX_IA64_MODE="32"
@@ -5644,12 +5684,12 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 5647 "configure"' > conftest.$ac_ext
-  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  echo '#line 5687 "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
    if test "$lt_cv_prog_gnu_ld" = yes; then
     case `/usr/bin/file conftest.$ac_objext` in
     *32-bit*)
@@ -5682,11 +5722,11 @@ ia64-*-hpux*)
 x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
   # Find out which ABI we are using.
   echo 'int i;' > conftest.$ac_ext
-  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
     case `/usr/bin/file conftest.o` in
     *32-bit*)
       case $host in
@@ -5729,9 +5769,9 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
   # On SCO OpenServer 5, we need -belf to get full-featured binaries.
   SAVE_CFLAGS="$CFLAGS"
   CFLAGS="$CFLAGS -belf"
-  { $as_echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
 $as_echo_n "checking whether the C compiler needs -belf... " >&6; }
-if test "${lt_cv_cc_needs_belf+set}" = set; then
+if test "${lt_cv_cc_needs_belf+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_ext=c
@@ -5740,11 +5780,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
-     cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -5755,38 +5791,13 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   lt_cv_cc_needs_belf=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       lt_cv_cc_needs_belf=no
+  lt_cv_cc_needs_belf=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
      ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -5794,7 +5805,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
 $as_echo "$lt_cv_cc_needs_belf" >&6; }
   if test x"$lt_cv_cc_needs_belf" != x"yes"; then
     # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
@@ -5804,11 +5815,11 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
 sparc*-*solaris*)
   # Find out which ABI we are using.
   echo 'int i;' > conftest.$ac_ext
-  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
     case `/usr/bin/file conftest.o` in
     *64-bit*)
       case $lt_cv_prog_gnu_ld in
@@ -5832,14 +5843,14 @@ ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
 $as_echo_n "checking how to run the C preprocessor... " >&6; }
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
 fi
 if test -z "$CPP"; then
-  if test "${ac_cv_prog_CPP+set}" = set; then
+  if test "${ac_cv_prog_CPP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
       # Double quotes because CPP needs to be expanded
@@ -5854,11 +5865,7 @@ do
   # <limits.h> exists even on freestanding compilers.
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #ifdef __STDC__
 # include <limits.h>
@@ -5867,78 +5874,34 @@ cat >>conftest.$ac_ext <<_ACEOF
 #endif
                     Syntax error
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_cpp "$LINENO"; then :
 
+else
   # Broken: fails on valid input.
 continue
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
   # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <ac_nonexistent.h>
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
+if ac_fn_c_try_cpp "$LINENO"; then :
   # Broken: success on invalid input.
 continue
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
   # Passes both tests.
 ac_preproc_ok=:
 break
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
 rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
+if $ac_preproc_ok; then :
   break
 fi
 
@@ -5950,7 +5913,7 @@ fi
 else
   ac_cv_prog_CPP=$CPP
 fi
-{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
 $as_echo "$CPP" >&6; }
 ac_preproc_ok=false
 for ac_c_preproc_warn_flag in '' yes
@@ -5961,11 +5924,7 @@ do
   # <limits.h> exists even on freestanding compilers.
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #ifdef __STDC__
 # include <limits.h>
@@ -5974,85 +5933,40 @@ cat >>conftest.$ac_ext <<_ACEOF
 #endif
                     Syntax error
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_cpp "$LINENO"; then :
 
+else
   # Broken: fails on valid input.
 continue
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
   # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <ac_nonexistent.h>
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
+if ac_fn_c_try_cpp "$LINENO"; then :
   # Broken: success on invalid input.
 continue
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
   # Passes both tests.
 ac_preproc_ok=:
 break
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
 rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
-  :
+if $ac_preproc_ok; then :
+
 else
-  { { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
 fi
 
 ac_ext=c
@@ -6062,16 +5976,12 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
 $as_echo_n "checking for ANSI C header files... " >&6; }
-if test "${ac_cv_header_stdc+set}" = set; then
+if test "${ac_cv_header_stdc+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdlib.h>
 #include <stdarg.h>
@@ -6086,48 +5996,23 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_header_stdc=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_header_stdc=no
+  ac_cv_header_stdc=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <string.h>
 
 _ACEOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then
-  :
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
 else
   ac_cv_header_stdc=no
 fi
@@ -6137,18 +6022,14 @@ 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 <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdlib.h>
 
 _ACEOF
 if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then
-  :
+  $EGREP "free" >/dev/null 2>&1; then :
+
 else
   ac_cv_header_stdc=no
 fi
@@ -6158,14 +6039,10 @@ 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
+  if test "$cross_compiling" = yes; then :
   :
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <ctype.h>
 #include <stdlib.h>
@@ -6192,117 +6069,34 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  :
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_c_try_run "$LINENO"; then :
 
-( exit $ac_status )
-ac_cv_header_stdc=no
+else
+  ac_cv_header_stdc=no
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-
 fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
 $as_echo "$ac_cv_header_stdc" >&6; }
 if test $ac_cv_header_stdc = yes; then
 
-cat >>confdefs.h <<\_ACEOF
-#define STDC_HEADERS 1
-_ACEOF
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
 
 fi
 
 # On IRIX 5.3, sys/types and inttypes.h are conflicting.
-
-
-
-
-
-
-
-
-
 for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
                  inttypes.h stdint.h unistd.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  eval "$as_ac_Header=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_Header=no"
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'` = yes; then
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+eval as_val=\$$as_ac_Header
+   if test "x$as_val" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 done
 
 
-
 for ac_header in dlfcn.h
-do
-as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
-$as_echo_n "checking $ac_header usability... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-#include <$ac_header>
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_header_compiler=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_header_compiler=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
-$as_echo_n "checking $ac_header presence... " >&6; }
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <$ac_header>
-_ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  ac_header_preproc=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-  ac_header_preproc=no
-fi
-
-rm -f conftest.err conftest.$ac_ext
-{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
-  yes:no: )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
-    ac_header_preproc=yes
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
-$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
-    ( cat <<\_ASBOX
-## ------------------------------------ ##
-## Report this to http://www.sqlite.org ##
-## ------------------------------------ ##
-_ASBOX
-     ) | sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
-$as_echo_n "checking for $ac_header... " >&6; }
-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  eval "$as_ac_Header=\$ac_header_preproc"
-fi
-ac_res=`eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-
-fi
-if test `eval 'as_val=${'$as_ac_Header'}
-                $as_echo "$as_val"'` = yes; then
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define HAVE_DLFCN_H 1
 _ACEOF
 
 fi
@@ -6476,9 +6132,9 @@ if test -z "$CXX"; then
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_CXX+set}" = set; then
+if test "${ac_cv_prog_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$CXX"; then
@@ -6489,24 +6145,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 CXX=$ac_cv_prog_CXX
 if test -n "$CXX"; then
-  { $as_echo "$as_me:$LINENO: result: $CXX" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
 $as_echo "$CXX" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -6520,9 +6176,9 @@ if test -z "$CXX"; then
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CXX"; then
@@ -6533,24 +6189,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_CXX="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
 if test -n "$ac_ct_CXX"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
 $as_echo "$ac_ct_CXX" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -6563,12 +6219,8 @@ done
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     CXX=$ac_ct_CXX
@@ -6578,53 +6230,36 @@ fi
   fi
 fi
 # Provide some information about the compiler.
-$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
 set X $ac_compile
 ac_compiler=$2
-{ (ac_try="$ac_compiler --version >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -6638,37 +6273,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_cxx_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
 if test $ac_compiler_gnu = yes; then
   GXX=yes
@@ -6677,20 +6291,16 @@ else
 fi
 ac_test_CXXFLAGS=${CXXFLAGS+set}
 ac_save_CXXFLAGS=$CXXFLAGS
-{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
 $as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if test "${ac_cv_prog_cxx_g+set}" = set; then
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_save_cxx_werror_flag=$ac_cxx_werror_flag
    ac_cxx_werror_flag=yes
    ac_cv_prog_cxx_g=no
    CXXFLAGS="-g"
-   cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -6701,35 +6311,11 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_cxx_try_compile "$LINENO"; then :
   ac_cv_prog_cxx_g=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       CXXFLAGS=""
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -6740,36 +6326,12 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_cxx_try_compile "$LINENO"; then :
 
-       ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
         CXXFLAGS="-g"
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -6780,42 +6342,17 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_cxx_try_compile "$LINENO"; then :
   ac_cv_prog_cxx_g=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
    ac_cxx_werror_flag=$ac_save_cxx_werror_flag
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
 $as_echo "$ac_cv_prog_cxx_g" >&6; }
 if test "$ac_test_CXXFLAGS" = set; then
   CXXFLAGS=$ac_save_CXXFLAGS
@@ -6840,9 +6377,9 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 
 depcc="$CXX"  am_compiler_list=
 
-{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
 $as_echo_n "checking dependency style of $depcc... " >&6; }
-if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
@@ -6930,7 +6467,7 @@ else
 fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
 CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
 
@@ -6957,10 +6494,10 @@ ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-{ $as_echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
 $as_echo_n "checking how to run the C++ preprocessor... " >&6; }
 if test -z "$CXXCPP"; then
-  if test "${ac_cv_prog_CXXCPP+set}" = set; then
+  if test "${ac_cv_prog_CXXCPP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
       # Double quotes because CXXCPP needs to be expanded
@@ -6975,11 +6512,7 @@ do
   # <limits.h> exists even on freestanding compilers.
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #ifdef __STDC__
 # include <limits.h>
@@ -6988,78 +6521,34 @@ cat >>conftest.$ac_ext <<_ACEOF
 #endif
                     Syntax error
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_cxx_try_cpp "$LINENO"; then :
 
+else
   # Broken: fails on valid input.
 continue
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
   # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <ac_nonexistent.h>
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       }; then
+if ac_fn_cxx_try_cpp "$LINENO"; then :
   # Broken: success on invalid input.
 continue
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
   # Passes both tests.
 ac_preproc_ok=:
 break
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
 rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
+if $ac_preproc_ok; then :
   break
 fi
 
@@ -7071,7 +6560,7 @@ fi
 else
   ac_cv_prog_CXXCPP=$CXXCPP
 fi
-{ $as_echo "$as_me:$LINENO: result: $CXXCPP" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
 $as_echo "$CXXCPP" >&6; }
 ac_preproc_ok=false
 for ac_cxx_preproc_warn_flag in '' yes
@@ -7082,11 +6571,7 @@ do
   # <limits.h> exists even on freestanding compilers.
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp. "Syntax error" is here to catch this case.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #ifdef __STDC__
 # include <limits.h>
@@ -7095,85 +6580,40 @@ cat >>conftest.$ac_ext <<_ACEOF
 #endif
                     Syntax error
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       }; then
-  :
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_cxx_try_cpp "$LINENO"; then :
 
+else
   # Broken: fails on valid input.
 continue
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
   # can be detected and how.
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <ac_nonexistent.h>
 _ACEOF
-if { (ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } >/dev/null && {
-        test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       }; then
+if ac_fn_cxx_try_cpp "$LINENO"; then :
   # Broken: success on invalid input.
 continue
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
   # Passes both tests.
 ac_preproc_ok=:
 break
 fi
-
 rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
 rm -f conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then
-  :
+if $ac_preproc_ok; then :
+
 else
-  { { $as_echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check
-See \`config.log' for more details." >&5
-$as_echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
 fi
 
 ac_ext=cpp
@@ -7194,9 +6634,9 @@ if test -n "$ac_tool_prefix"; then
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_F77+set}" = set; then
+if test "${ac_cv_prog_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$F77"; then
@@ -7207,24 +6647,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 F77=$ac_cv_prog_F77
 if test -n "$F77"; then
-  { $as_echo "$as_me:$LINENO: result: $F77" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F77" >&5
 $as_echo "$F77" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -7238,9 +6678,9 @@ if test -z "$F77"; then
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_F77+set}" = set; then
+if test "${ac_cv_prog_ac_ct_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_F77"; then
@@ -7251,24 +6691,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_F77="$ac_prog"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_F77=$ac_cv_prog_ac_ct_F77
 if test -n "$ac_ct_F77"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_F77" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_F77" >&5
 $as_echo "$ac_ct_F77" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -7281,12 +6721,8 @@ done
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     F77=$ac_ct_F77
 
 
 # Provide some information about the compiler.
-$as_echo "$as_me:$LINENO: checking for Fortran 77 compiler version" >&5
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 compiler version" >&5
 set X $ac_compile
 ac_compiler=$2
-{ (ac_try="$ac_compiler --version >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler --version >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -v >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -v >&5") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (ac_try="$ac_compiler -V >&5"
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compiler -V >&5") 2>&5
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 rm -f a.out
 
 # If we don't use `.F' as extension, the preprocessor is not run on the
 # input file.  (Note that this only needs to work for GNU compilers.)
 ac_save_ext=$ac_ext
 ac_ext=F
-{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5
 $as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; }
-if test "${ac_cv_f77_compiler_gnu+set}" = set; then
+if test "${ac_cv_f77_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
+  cat > conftest.$ac_ext <<_ACEOF
       program main
 #ifndef __GNUC__
        choke me
-#endif
-
-      end
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_f77_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+#endif
+
+      end
+_ACEOF
+if ac_fn_f77_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_f77_compiler_gnu=$ac_compiler_gnu
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_compiler_gnu" >&5
 $as_echo "$ac_cv_f77_compiler_gnu" >&6; }
 ac_ext=$ac_save_ext
 ac_test_FFLAGS=${FFLAGS+set}
 ac_save_FFLAGS=$FFLAGS
 FFLAGS=
-{ $as_echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5
 $as_echo_n "checking whether $F77 accepts -g... " >&6; }
-if test "${ac_cv_prog_f77_g+set}" = set; then
+if test "${ac_cv_prog_f77_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   FFLAGS=-g
-cat >conftest.$ac_ext <<_ACEOF
+cat > conftest.$ac_ext <<_ACEOF
       program main
 
       end
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_f77_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_f77_try_compile "$LINENO"; then :
   ac_cv_prog_f77_g=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_prog_f77_g=no
+  ac_cv_prog_f77_g=no
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_g" >&5
 $as_echo "$ac_cv_prog_f77_g" >&6; }
 if test "$ac_test_FFLAGS" = set; then
   FFLAGS=$ac_save_FFLAGS
@@ -7460,9 +6841,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers!
 
 # find the maximum length of command line arguments
-{ $as_echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
 $as_echo_n "checking the maximum length of command line arguments... " >&6; }
-if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
     i=0
@@ -7569,10 +6950,10 @@ else
 fi
 
 if test -n $lt_cv_sys_max_cmd_len ; then
-  { $as_echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
 $as_echo "$lt_cv_sys_max_cmd_len" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: none" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
 $as_echo "none" >&6; }
 fi
 
@@ -7580,9 +6961,9 @@ fi
 
 
 # Check for command to grab the raw symbol name followed by C symbol from nm.
-{ $as_echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
-if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
 
@@ -7685,18 +7066,18 @@ void nm_test_func(){}
 int main(){nm_test_var='a';nm_test_func();return(0);}
 EOF
 
-  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
     # Now try to grab the symbols.
     nlist=conftest.nm
-    if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5
   (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && test -s "$nlist"; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
       # Try sorting and uniquifying the output.
       if sort "$nlist" | uniq > "$nlist"T; then
        mv -f "$nlist"T "$nlist"
@@ -7747,11 +7128,11 @@ EOF
          lt_save_CFLAGS="$CFLAGS"
          LIBS="conftstm.$ac_objext"
          CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
-         if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
   (eval $ac_link) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && test -s conftest${ac_exeext}; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
            pipe_works=yes
          fi
          LIBS="$lt_save_LIBS"
@@ -7785,16 +7166,16 @@ if test -z "$lt_cv_sys_global_symbol_pipe"; then
   lt_cv_sys_global_symbol_to_cdecl=
 fi
 if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
-  { $as_echo "$as_me:$LINENO: result: failed" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
 $as_echo "failed" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: ok" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
 $as_echo "ok" >&6; }
 fi
 
-{ $as_echo "$as_me:$LINENO: checking for objdir" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
 $as_echo_n "checking for objdir... " >&6; }
-if test "${lt_cv_objdir+set}" = set; then
+if test "${lt_cv_objdir+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   rm -f .libs 2>/dev/null
@@ -7807,7 +7188,7 @@ else
 fi
 rmdir .libs 2>/dev/null
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
 $as_echo "$lt_cv_objdir" >&6; }
 objdir=$lt_cv_objdir
 
@@ -7859,9 +7240,9 @@ with_gnu_ld="$lt_cv_prog_gnu_ld"
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ar; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_AR+set}" = set; then
+if test "${ac_cv_prog_AR+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$AR"; then
@@ -7872,24 +7253,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 AR=$ac_cv_prog_AR
 if test -n "$AR"; then
-  { $as_echo "$as_me:$LINENO: result: $AR" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
 $as_echo "$AR" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -7899,9 +7280,9 @@ if test -z "$ac_cv_prog_AR"; then
   ac_ct_AR=$AR
   # Extract the first word of "ar", so it can be a program name with args.
 set dummy ar; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_AR"; then
@@ -7912,24 +7293,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_AR="ar"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_AR=$ac_cv_prog_ac_ct_AR
 if test -n "$ac_ct_AR"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
 $as_echo "$ac_ct_AR" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -7938,12 +7319,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     AR=$ac_ct_AR
@@ -7955,9 +7332,9 @@ fi
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_RANLIB+set}" = set; then
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$RANLIB"; then
@@ -7968,24 +7345,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 RANLIB=$ac_cv_prog_RANLIB
 if test -n "$RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
 $as_echo "$RANLIB" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -7995,9 +7372,9 @@ if test -z "$ac_cv_prog_RANLIB"; then
   ac_ct_RANLIB=$RANLIB
   # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_RANLIB"; then
@@ -8008,24 +7385,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
 if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
 $as_echo "$ac_ct_RANLIB" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -8034,12 +7411,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     RANLIB=$ac_ct_RANLIB
@@ -8051,9 +7424,9 @@ fi
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
 set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_STRIP+set}" = set; then
+if test "${ac_cv_prog_STRIP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$STRIP"; then
@@ -8064,24 +7437,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 STRIP=$ac_cv_prog_STRIP
 if test -n "$STRIP"; then
-  { $as_echo "$as_me:$LINENO: result: $STRIP" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
 $as_echo "$STRIP" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -8091,9 +7464,9 @@ if test -z "$ac_cv_prog_STRIP"; then
   ac_ct_STRIP=$STRIP
   # Extract the first word of "strip", so it can be a program name with args.
 set dummy strip; ac_word=$2
-{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_STRIP"; then
@@ -8104,24 +7477,24 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
   if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
     ac_cv_prog_ac_ct_STRIP="strip"
-    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
 if test -n "$ac_ct_STRIP"; then
-  { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
 $as_echo "$ac_ct_STRIP" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -8130,12 +7503,8 @@ fi
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
-{ $as_echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&5
-$as_echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
-whose name does not start with the host triplet.  If you think this
-configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
     STRIP=$ac_ct_STRIP
@@ -8198,9 +7567,9 @@ cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
 case $deplibs_check_method in
 file_magic*)
   if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    { $as_echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   case $MAGIC_CMD in
@@ -8251,18 +7620,18 @@ fi
 
 MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
 if test -n "$MAGIC_CMD"; then
-  { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
 $as_echo "$MAGIC_CMD" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 if test -z "$lt_cv_path_MAGIC_CMD"; then
   if test -n "$ac_tool_prefix"; then
-    { $as_echo "$as_me:$LINENO: checking for file" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
 $as_echo_n "checking for file... " >&6; }
-if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   case $MAGIC_CMD in
@@ -8313,10 +7682,10 @@ fi
 
 MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
 if test -n "$MAGIC_CMD"; then
-  { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
 $as_echo "$MAGIC_CMD" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
@@ -8333,7 +7702,7 @@ enable_dlopen=no
 enable_win32_dll=no
 
 # Check whether --enable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then
+if test "${enable_libtool_lock+set}" = set; then :
   enableval=$enable_libtool_lock;
 fi
 
@@ -8341,7 +7710,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
 
 
 # Check whether --with-pic was given.
-if test "${with_pic+set}" = set; then
+if test "${with_pic+set}" = set; then :
   withval=$with_pic; pic_mode="$withval"
 else
   pic_mode=default
@@ -8404,9 +7773,9 @@ if test "$GCC" = yes; then
   lt_prog_compiler_no_builtin_flag=' -fno-builtin'
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_rtti_exceptions=no
@@ -8422,11 +7791,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8425: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:7794: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8429: \$? = $ac_status" >&5
+   echo "$as_me:7798: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8439,7 +7808,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
 
 if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
@@ -8454,7 +7823,7 @@ lt_prog_compiler_wl=
 lt_prog_compiler_pic=
 lt_prog_compiler_static=
 
-{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
 $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
 
   if test "$GCC" = yes; then
@@ -8664,7 +8033,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
 $as_echo "$lt_prog_compiler_pic" >&6; }
 
 #
@@ -8672,9 +8041,9 @@ $as_echo "$lt_prog_compiler_pic" >&6; }
 #
 if test -n "$lt_prog_compiler_pic"; then
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
-if test "${lt_prog_compiler_pic_works+set}" = set; then
+if test "${lt_prog_compiler_pic_works+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_pic_works=no
@@ -8690,11 +8059,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8693: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8062: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8697: \$? = $ac_status" >&5
+   echo "$as_me:8066: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8707,7 +8076,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works" >&5
 $as_echo "$lt_prog_compiler_pic_works" >&6; }
 
 if test x"$lt_prog_compiler_pic_works" = xyes; then
@@ -8735,9 +8104,9 @@ esac
 # Check to make sure the static flag actually works.
 #
 wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
-{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test "${lt_prog_compiler_static_works+set}" = set; then
+if test "${lt_prog_compiler_static_works+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_static_works=no
@@ -8763,7 +8132,7 @@ else
    LDFLAGS="$save_LDFLAGS"
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works" >&5
 $as_echo "$lt_prog_compiler_static_works" >&6; }
 
 if test x"$lt_prog_compiler_static_works" = xyes; then
@@ -8773,9 +8142,9 @@ else
 fi
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_c_o=no
@@ -8794,11 +8163,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8797: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8166: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8801: \$? = $ac_status" >&5
+   echo "$as_me:8170: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -8820,14 +8189,14 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
 $as_echo "$lt_cv_prog_compiler_c_o" >&6; }
 
 
 hard_links="nottested"
 if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
   # do not overwrite the value of need_locks provided by the user
-  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
   hard_links=yes
   $rm conftest*
@@ -8835,10 +8204,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   touch conftest.a
   ln conftest.a conftest.b 2>&5 || hard_links=no
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
   if test "$hard_links" = no; then
-    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
@@ -8846,7 +8215,7 @@ else
   need_locks=no
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
 
   runpath_var=
@@ -9246,11 +8615,7 @@ _LT_EOF
        # -berok will link without error, but may produce a broken library.
        allow_undefined_flag='-berok'
        # Determine the default libpath from the value encoded in an empty executable.
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -9261,43 +8626,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -9309,11 +8647,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
          archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
        else
         # Determine the default libpath from the value encoded in an empty executable.
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -9324,43 +8658,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
         hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -9808,7 +9115,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
 $as_echo "$ld_shlibs" >&6; }
 test "$ld_shlibs" = no && can_build_shared=no
 
@@ -9829,16 +9136,16 @@ x|xyes)
       # Test whether the compiler implicitly links with -lc since on some
       # systems, -lgcc has to come before -lc. If gcc already passes -lc
       # to ld, don't add -lc before -lgcc.
-      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
       $rm conftest*
       printf "$lt_simple_compile_test_code" > conftest.$ac_ext
 
-      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } 2>conftest.err; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
         soname=conftest
         lib=conftest
         libobjs=conftest.$ac_objext
@@ -9852,11 +9159,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         libname=conftest
         lt_save_allow_undefined_flag=$allow_undefined_flag
         allow_undefined_flag=
-        if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5
   (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
         then
          archive_cmds_need_lc=no
         else
@@ -9867,7 +9174,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         cat conftest.err 1>&5
       fi
       $rm conftest*
-      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5
 $as_echo "$archive_cmds_need_lc" >&6; }
       ;;
     esac
@@ -9875,7 +9182,7 @@ $as_echo "$archive_cmds_need_lc" >&6; }
   ;;
 esac
 
-{ $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
 $as_echo_n "checking dynamic linker characteristics... " >&6; }
 library_names_spec=
 libname_spec='lib$name'
@@ -10463,7 +9770,7 @@ uts4*)
   dynamic_linker=no
   ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
 test "$dynamic_linker" = no && can_build_shared=no
 
@@ -10472,7 +9779,7 @@ if test "$GCC" = yes; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-{ $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
 $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action=
 if test -n "$hardcode_libdir_flag_spec" || \
@@ -10497,7 +9804,7 @@ else
   # directories.
   hardcode_action=unsupported
 fi
-{ $as_echo "$as_me:$LINENO: result: $hardcode_action" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
 $as_echo "$hardcode_action" >&6; }
 
 if test "$hardcode_action" = relink; then
 
 striplib=
 old_striplib=
-{ $as_echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
 $as_echo_n "checking whether stripping libraries is possible... " >&6; }
 if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then
   test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
   test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  { $as_echo "$as_me:$LINENO: result: yes" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 else
 # FIXME - insert some real tests, host_os isn't really good enough
@@ -10524,15 +9831,15 @@ else
    darwin*)
        if test -n "$STRIP" ; then
          striplib="$STRIP -x"
-         { $as_echo "$as_me:$LINENO: result: yes" >&5
+         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
        else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
        ;;
    *)
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
     ;;
   esac
@@ -10565,18 +9872,14 @@ else
 
   darwin*)
   # if libdl is installed we need to link against it
-    { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
 $as_echo_n "checking for dlopen in -ldl... " >&6; }
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
 LIBS="-ldl  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -10594,43 +9897,18 @@ return dlopen ();
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_lib_dl_dlopen=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_dl_dlopen=no
+  ac_cv_lib_dl_dlopen=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
 $as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test $ac_cv_lib_dl_dlopen = yes; then
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
   lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
 else
 
    ;;
 
   *)
-    { $as_echo "$as_me:$LINENO: checking for shl_load" >&5
-$as_echo_n "checking for shl_load... " >&6; }
-if test "${ac_cv_func_shl_load+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define shl_load innocuous_shl_load
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char shl_load (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef shl_load
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char shl_load ();
-/* 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_shl_load || defined __stub___shl_load
-choke me
-#endif
-
-int
-main ()
-{
-return shl_load ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_func_shl_load=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_func_shl_load=no
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
-$as_echo "$ac_cv_func_shl_load" >&6; }
-if test $ac_cv_func_shl_load = yes; then
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = x""yes; then :
   lt_cv_dlopen="shl_load"
 else
-  { $as_echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
 $as_echo_n "checking for shl_load in -ldld... " >&6; }
-if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
 LIBS="-ldld  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -10760,145 +9950,32 @@ return shl_load ();
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_lib_dld_shl_load=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_dld_shl_load=no
+  ac_cv_lib_dld_shl_load=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
 $as_echo "$ac_cv_lib_dld_shl_load" >&6; }
-if test $ac_cv_lib_dld_shl_load = yes; then
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
   lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"
 else
-  { $as_echo "$as_me:$LINENO: checking for dlopen" >&5
-$as_echo_n "checking for dlopen... " >&6; }
-if test "${ac_cv_func_dlopen+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define dlopen innocuous_dlopen
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char dlopen (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef dlopen
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-/* 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_dlopen || defined __stub___dlopen
-choke me
-#endif
-
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_func_dlopen=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_func_dlopen=no
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
-$as_echo "$ac_cv_func_dlopen" >&6; }
-if test $ac_cv_func_dlopen = yes; then
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
   lt_cv_dlopen="dlopen"
 else
-  { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
 $as_echo_n "checking for dlopen in -ldl... " >&6; }
-if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
 LIBS="-ldl  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -10916,57 +9993,28 @@ return dlopen ();
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_lib_dl_dlopen=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_dl_dlopen=no
+  ac_cv_lib_dl_dlopen=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
 $as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test $ac_cv_lib_dl_dlopen = yes; then
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
   lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
 else
-  { $as_echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
 $as_echo_n "checking for dlopen in -lsvld... " >&6; }
-if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
 LIBS="-lsvld  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -10984,57 +10032,28 @@ return dlopen ();
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_lib_svld_dlopen=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_svld_dlopen=no
+  ac_cv_lib_svld_dlopen=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
 $as_echo "$ac_cv_lib_svld_dlopen" >&6; }
-if test $ac_cv_lib_svld_dlopen = yes; then
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
   lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
 else
-  { $as_echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
 $as_echo_n "checking for dld_link in -ldld... " >&6; }
-if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
 LIBS="-ldld  $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -11052,43 +10071,18 @@ return dld_link ();
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_lib_dld_dld_link=yes
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_lib_dld_dld_link=no
+  ac_cv_lib_dld_dld_link=no
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
 $as_echo "$ac_cv_lib_dld_dld_link" >&6; }
-if test $ac_cv_lib_dld_dld_link = yes; then
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
   lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"
 fi
 
@@ -11127,9 +10121,9 @@ fi
     save_LIBS="$LIBS"
     LIBS="$lt_cv_dlopen_libs $LIBS"
 
-    { $as_echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
 $as_echo_n "checking whether a program can dlopen itself... " >&6; }
-if test "${lt_cv_dlopen_self+set}" = set; then
+if test "${lt_cv_dlopen_self+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
          if test "$cross_compiling" = yes; then :
@@ -11138,7 +10132,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11141 "configure"
+#line 10135 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11201,11 +10195,11 @@ int main ()
     exit (status);
 }
 EOF
-  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
   (eval $ac_link) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
     (./conftest; exit; ) >&5 2>/dev/null
     lt_status=$?
     case x$lt_status in
@@ -11222,14 +10216,14 @@ rm -fr conftest*
 
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
 $as_echo "$lt_cv_dlopen_self" >&6; }
 
     if test "x$lt_cv_dlopen_self" = xyes; then
       wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
-      { $as_echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
-if test "${lt_cv_dlopen_self_static+set}" = set; then
+if test "${lt_cv_dlopen_self_static+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
          if test "$cross_compiling" = yes; then :
@@ -11238,7 +10232,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 11241 "configure"
+#line 10235 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11301,11 +10295,11 @@ int main ()
     exit (status);
 }
 EOF
-  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
   (eval $ac_link) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
     (./conftest; exit; ) >&5 2>/dev/null
     lt_status=$?
     case x$lt_status in
@@ -11322,7 +10316,7 @@ rm -fr conftest*
 
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
 $as_echo "$lt_cv_dlopen_self_static" >&6; }
     fi
 
 
 
 # Report which library types will actually be built
-{ $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
 $as_echo_n "checking if libtool supports shared libraries... " >&6; }
-{ $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
 $as_echo "$can_build_shared" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
 $as_echo_n "checking whether to build shared libraries... " >&6; }
 test "$can_build_shared" = "no" && enable_shared=no
 
@@ -11371,14 +10365,14 @@ aix4* | aix5*)
   fi
     ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $enable_shared" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
 $as_echo "$enable_shared" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
 $as_echo_n "checking whether to build static libraries... " >&6; }
 # Make sure either enable_shared or enable_static is yes.
 test "$enable_shared" = yes || enable_static=yes
-{ $as_echo "$as_me:$LINENO: result: $enable_static" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
 $as_echo "$enable_static" >&6; }
 
 # The else clause should only fire when bootstrapping the
@@ -11470,7 +10464,7 @@ if test -f "$ltmain"; then
 cfgfile="${ofile}T"
   trap "$rm \"$cfgfile\"; exit 1" 1 2 15
   $rm -f "$cfgfile"
-  { $as_echo "$as_me:$LINENO: creating $ofile" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5
 $as_echo "$as_me: creating $ofile" >&6;}
 
   cat <<__EOF__ >> "$cfgfile"
@@ -11872,24 +10866,24 @@ CC="$lt_save_CC"
 
 
 # Check whether --with-tags was given.
-if test "${with_tags+set}" = set; then
+if test "${with_tags+set}" = set; then :
   withval=$with_tags; tagnames="$withval"
 fi
 
 
 if test -f "$ltmain" && test -n "$tagnames"; then
   if test ! -f "${ofile}"; then
-    { $as_echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not exist" >&5
 $as_echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;}
   fi
 
   if test -z "$LTCC"; then
     eval "`$SHELL ${ofile} --config | grep '^LTCC='`"
     if test -z "$LTCC"; then
-      { $as_echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not look like a libtool script" >&5
 $as_echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;}
     else
-      { $as_echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5
 $as_echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
     fi
   fi
@@ -11907,17 +10901,13 @@ $as_echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;}
     # Check whether tagname contains only valid characters
     case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in
     "") ;;
-    *)  { { $as_echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5
-$as_echo "$as_me: error: invalid tag name: $tagname" >&2;}
-   { (exit 1); exit 1; }; }
+    *)  as_fn_error "invalid tag name: $tagname" "$LINENO" 5
        ;;
     esac
 
     if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null
     then
-      { { $as_echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5
-$as_echo "$as_me: error: tag name \"$tagname\" already exists" >&2;}
-   { (exit 1); exit 1; }; }
+      as_fn_error "tag name \"$tagname\" already exists" "$LINENO" 5
     fi
 
     # Update the list of available tags.
@@ -12049,7 +11039,7 @@ if test "$GXX" = yes; then
 
 
 # Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then
+if test "${with_gnu_ld+set}" = set; then :
   withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
 else
   with_gnu_ld=no
@@ -12058,7 +11048,7 @@ fi
 ac_prog=ld
 if test "$GCC" = yes; then
   # Check if gcc -print-prog-name=ld gives a path.
-  { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
 $as_echo_n "checking for ld used by $CC... " >&6; }
   case $host in
   *-*-mingw*)
@@ -12088,13 +11078,13 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
     ;;
   esac
 elif test "$with_gnu_ld" = yes; then
-  { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
 $as_echo_n "checking for GNU ld... " >&6; }
 else
-  { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
 $as_echo_n "checking for non-GNU ld... " >&6; }
 fi
-if test "${lt_cv_path_LD+set}" = set; then
+if test "${lt_cv_path_LD+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$LD"; then
 
 LD="$lt_cv_path_LD"
 if test -n "$LD"; then
-  { $as_echo "$as_me:$LINENO: result: $LD" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
 $as_echo "$LD" >&6; }
 else
-  { $as_echo "$as_me:$LINENO: result: no" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
-test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
-$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
-   { (exit 1); exit 1; }; }
-{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if test "${lt_cv_prog_gnu_ld+set}" = set; then
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   # I'd rather use --version here, but apparently some GNU lds only accept -v.
@@ -12149,7 +11137,7 @@ case `$LD -v 2>&1 </dev/null` in
   ;;
 esac
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
 $as_echo "$lt_cv_prog_gnu_ld" >&6; }
 with_gnu_ld=$lt_cv_prog_gnu_ld
 
@@ -12200,7 +11188,7 @@ else
 fi
 
 # PORTME: fill in a description of your system's C++ link characteristics
-{ $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
 ld_shlibs_CXX=yes
 case $host_os in
@@ -12297,11 +11285,7 @@ case $host_os in
       # -berok will link without error, but may produce a broken library.
       allow_undefined_flag_CXX='-berok'
       # Determine the default libpath from the value encoded in an empty executable.
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -12312,43 +11296,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_cxx_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
       hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -12361,11 +11318,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
        archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
       else
        # Determine the default libpath from the value encoded in an empty executable.
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -12376,43 +11329,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_cxx_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_cxx_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
        hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -13142,7 +12068,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
     ld_shlibs_CXX=no
     ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
 $as_echo "$ld_shlibs_CXX" >&6; }
 test "$ld_shlibs_CXX" = no && can_build_shared=no
 
@@ -13160,11 +12086,11 @@ private:
 };
 EOF
 
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
   # Parse the compiler output and extract the necessary
   # objects, libraries and library flags.
 
@@ -13282,7 +12208,7 @@ lt_prog_compiler_wl_CXX=
 lt_prog_compiler_pic_CXX=
 lt_prog_compiler_static_CXX=
 
-{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
 $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
 
   # C++ specific cases for pic, static, wl, etc.
@@ -13556,7 +12482,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5
 $as_echo "$lt_prog_compiler_pic_CXX" >&6; }
 
 #
@@ -13564,9 +12490,9 @@ $as_echo "$lt_prog_compiler_pic_CXX" >&6; }
 #
 if test -n "$lt_prog_compiler_pic_CXX"; then
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
-if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then
+if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_pic_works_CXX=no
@@ -13582,11 +12508,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13585: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:12511: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:13589: \$? = $ac_status" >&5
+   echo "$as_me:12515: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -13599,7 +12525,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_CXX" >&5
 $as_echo "$lt_prog_compiler_pic_works_CXX" >&6; }
 
 if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then
@@ -13627,9 +12553,9 @@ esac
 # Check to make sure the static flag actually works.
 #
 wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
-{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test "${lt_prog_compiler_static_works_CXX+set}" = set; then
+if test "${lt_prog_compiler_static_works_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_static_works_CXX=no
@@ -13655,7 +12581,7 @@ else
    LDFLAGS="$save_LDFLAGS"
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_CXX" >&5
 $as_echo "$lt_prog_compiler_static_works_CXX" >&6; }
 
 if test x"$lt_prog_compiler_static_works_CXX" = xyes; then
@@ -13665,9 +12591,9 @@ else
 fi
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_c_o_CXX=no
@@ -13686,11 +12612,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:13689: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:12615: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:13693: \$? = $ac_status" >&5
+   echo "$as_me:12619: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -13712,14 +12638,14 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
 
 
 hard_links="nottested"
 if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
   # do not overwrite the value of need_locks provided by the user
-  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
   hard_links=yes
   $rm conftest*
@@ -13727,10 +12653,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   touch conftest.a
   ln conftest.a conftest.b 2>&5 || hard_links=no
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
   if test "$hard_links" = no; then
-    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
@@ -13738,7 +12664,7 @@ else
   need_locks=no
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
 
   export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
@@ -13763,7 +12689,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   ;;
   esac
 
-{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
 $as_echo "$ld_shlibs_CXX" >&6; }
 test "$ld_shlibs_CXX" = no && can_build_shared=no
 
@@ -13784,16 +12710,16 @@ x|xyes)
       # Test whether the compiler implicitly links with -lc since on some
       # systems, -lgcc has to come before -lc. If gcc already passes -lc
       # to ld, don't add -lc before -lgcc.
-      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
       $rm conftest*
       printf "$lt_simple_compile_test_code" > conftest.$ac_ext
 
-      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } 2>conftest.err; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
         soname=conftest
         lib=conftest
         libobjs=conftest.$ac_objext
@@ -13807,11 +12733,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         libname=conftest
         lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
         allow_undefined_flag_CXX=
-        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5
   (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
         then
          archive_cmds_need_lc_CXX=no
         else
@@ -13822,7 +12748,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         cat conftest.err 1>&5
       fi
       $rm conftest*
-      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5
 $as_echo "$archive_cmds_need_lc_CXX" >&6; }
       ;;
     esac
@@ -13830,7 +12756,7 @@ $as_echo "$archive_cmds_need_lc_CXX" >&6; }
   ;;
 esac
 
-{ $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
 $as_echo_n "checking dynamic linker characteristics... " >&6; }
 library_names_spec=
 libname_spec='lib$name'
@@ -14418,7 +13344,7 @@ uts4*)
   dynamic_linker=no
   ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
 test "$dynamic_linker" = no && can_build_shared=no
 
@@ -14427,7 +13353,7 @@ if test "$GCC" = yes; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-{ $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
 $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action_CXX=
 if test -n "$hardcode_libdir_flag_spec_CXX" || \
@@ -14452,7 +13378,7 @@ else
   # directories.
   hardcode_action_CXX=unsupported
 fi
-{ $as_echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
 $as_echo "$hardcode_action_CXX" >&6; }
 
 if test "$hardcode_action_CXX" = relink; then
@@ -14978,12 +13904,12 @@ done
 cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
 
 
-{ $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
 $as_echo_n "checking if libtool supports shared libraries... " >&6; }
-{ $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
 $as_echo "$can_build_shared" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
 $as_echo_n "checking whether to build shared libraries... " >&6; }
 test "$can_build_shared" = "no" && enable_shared=no
 
@@ -15003,14 +13929,14 @@ aix4* | aix5*)
   fi
   ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $enable_shared" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
 $as_echo "$enable_shared" >&6; }
 
-{ $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
 $as_echo_n "checking whether to build static libraries... " >&6; }
 # Make sure either enable_shared or enable_static is yes.
 test "$enable_shared" = yes || enable_static=yes
-{ $as_echo "$as_me:$LINENO: result: $enable_static" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
 $as_echo "$enable_static" >&6; }
 
 GCC_F77="$G77"
@@ -15020,7 +13946,7 @@ lt_prog_compiler_wl_F77=
 lt_prog_compiler_pic_F77=
 lt_prog_compiler_static_F77=
 
-{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
 $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
 
   if test "$GCC" = yes; then
@@ -15230,7 +14156,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_F77" >&5
 $as_echo "$lt_prog_compiler_pic_F77" >&6; }
 
 #
@@ -15238,9 +14164,9 @@ $as_echo "$lt_prog_compiler_pic_F77" >&6; }
 #
 if test -n "$lt_prog_compiler_pic_F77"; then
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... " >&6; }
-if test "${lt_prog_compiler_pic_works_F77+set}" = set; then
+if test "${lt_prog_compiler_pic_works_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_pic_works_F77=no
@@ -15256,11 +14182,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15259: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14185: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:15263: \$? = $ac_status" >&5
+   echo "$as_me:14189: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -15273,7 +14199,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_F77" >&5
 $as_echo "$lt_prog_compiler_pic_works_F77" >&6; }
 
 if test x"$lt_prog_compiler_pic_works_F77" = xyes; then
@@ -15301,9 +14227,9 @@ esac
 # Check to make sure the static flag actually works.
 #
 wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\"
-{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test "${lt_prog_compiler_static_works_F77+set}" = set; then
+if test "${lt_prog_compiler_static_works_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_static_works_F77=no
@@ -15329,7 +14255,7 @@ else
    LDFLAGS="$save_LDFLAGS"
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_F77" >&5
 $as_echo "$lt_prog_compiler_static_works_F77" >&6; }
 
 if test x"$lt_prog_compiler_static_works_F77" = xyes; then
@@ -15339,9 +14265,9 @@ else
 fi
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then
+if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_c_o_F77=no
@@ -15360,11 +14286,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15363: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14289: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:15367: \$? = $ac_status" >&5
+   echo "$as_me:14293: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -15386,14 +14312,14 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_F77" >&5
 $as_echo "$lt_cv_prog_compiler_c_o_F77" >&6; }
 
 
 hard_links="nottested"
 if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then
   # do not overwrite the value of need_locks provided by the user
-  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
   hard_links=yes
   $rm conftest*
@@ -15401,10 +14327,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   touch conftest.a
   ln conftest.a conftest.b 2>&5 || hard_links=no
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
   if test "$hard_links" = no; then
-    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
@@ -15412,7 +14338,7 @@ else
   need_locks=no
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
 
   runpath_var=
@@ -15812,48 +14738,21 @@ _LT_EOF
        # -berok will link without error, but may produce a broken library.
        allow_undefined_flag_F77='-berok'
        # Determine the default libpath from the value encoded in an empty executable.
-       cat >conftest.$ac_ext <<_ACEOF
+       cat > conftest.$ac_ext <<_ACEOF
       program main
 
       end
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_f77_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_f77_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
        hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -15865,48 +14764,21 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
          archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
        else
         # Determine the default libpath from the value encoded in an empty executable.
-        cat >conftest.$ac_ext <<_ACEOF
+        cat > conftest.$ac_ext <<_ACEOF
       program main
 
       end
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_f77_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_f77_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
         hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -16354,7 +15226,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_F77" >&5
 $as_echo "$ld_shlibs_F77" >&6; }
 test "$ld_shlibs_F77" = no && can_build_shared=no
 
@@ -16375,16 +15247,16 @@ x|xyes)
       # Test whether the compiler implicitly links with -lc since on some
       # systems, -lgcc has to come before -lc. If gcc already passes -lc
       # to ld, don't add -lc before -lgcc.
-      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
       $rm conftest*
       printf "$lt_simple_compile_test_code" > conftest.$ac_ext
 
-      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } 2>conftest.err; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
         soname=conftest
         lib=conftest
         libobjs=conftest.$ac_objext
@@ -16398,11 +15270,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         libname=conftest
         lt_save_allow_undefined_flag=$allow_undefined_flag_F77
         allow_undefined_flag_F77=
-        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5
   (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
         then
          archive_cmds_need_lc_F77=no
         else
@@ -16413,7 +15285,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         cat conftest.err 1>&5
       fi
       $rm conftest*
-      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_F77" >&5
 $as_echo "$archive_cmds_need_lc_F77" >&6; }
       ;;
     esac
@@ -16421,7 +15293,7 @@ $as_echo "$archive_cmds_need_lc_F77" >&6; }
   ;;
 esac
 
-{ $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
 $as_echo_n "checking dynamic linker characteristics... " >&6; }
 library_names_spec=
 libname_spec='lib$name'
@@ -17009,7 +15881,7 @@ uts4*)
   dynamic_linker=no
   ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
 test "$dynamic_linker" = no && can_build_shared=no
 
@@ -17018,7 +15890,7 @@ if test "$GCC" = yes; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-{ $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
 $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action_F77=
 if test -n "$hardcode_libdir_flag_spec_F77" || \
@@ -17043,7 +15915,7 @@ else
   # directories.
   hardcode_action_F77=unsupported
 fi
-{ $as_echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_F77" >&5
 $as_echo "$hardcode_action_F77" >&6; }
 
 if test "$hardcode_action_F77" = relink; then
@@ -17548,9 +16420,9 @@ if test "$GCC" = yes; then
   lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin'
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_rtti_exceptions=no
@@ -17566,11 +16438,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17569: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16441: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:17573: \$? = $ac_status" >&5
+   echo "$as_me:16445: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -17583,7 +16455,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
 
 if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
@@ -17598,7 +16470,7 @@ lt_prog_compiler_wl_GCJ=
 lt_prog_compiler_pic_GCJ=
 lt_prog_compiler_static_GCJ=
 
-{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
 $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
 
   if test "$GCC" = yes; then
@@ -17808,7 +16680,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_GCJ" >&5
 $as_echo "$lt_prog_compiler_pic_GCJ" >&6; }
 
 #
@@ -17816,9 +16688,9 @@ $as_echo "$lt_prog_compiler_pic_GCJ" >&6; }
 #
 if test -n "$lt_prog_compiler_pic_GCJ"; then
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5
 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... " >&6; }
-if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then
+if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_pic_works_GCJ=no
@@ -17834,11 +16706,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17837: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16709: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:17841: \$? = $ac_status" >&5
+   echo "$as_me:16713: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -17851,7 +16723,7 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_GCJ" >&5
 $as_echo "$lt_prog_compiler_pic_works_GCJ" >&6; }
 
 if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then
@@ -17879,9 +16751,9 @@ esac
 # Check to make sure the static flag actually works.
 #
 wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\"
-{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then
+if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_prog_compiler_static_works_GCJ=no
@@ -17907,7 +16779,7 @@ else
    LDFLAGS="$save_LDFLAGS"
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_GCJ" >&5
 $as_echo "$lt_prog_compiler_static_works_GCJ" >&6; }
 
 if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then
@@ -17917,9 +16789,9 @@ else
 fi
 
 
-{ $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then
+if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_c_o_GCJ=no
@@ -17938,11 +16810,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:17941: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16813: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:17945: \$? = $ac_status" >&5
+   echo "$as_me:16817: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -17964,14 +16836,14 @@ else
    $rm conftest*
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_GCJ" >&5
 $as_echo "$lt_cv_prog_compiler_c_o_GCJ" >&6; }
 
 
 hard_links="nottested"
 if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then
   # do not overwrite the value of need_locks provided by the user
-  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
   hard_links=yes
   $rm conftest*
@@ -17979,10 +16851,10 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   touch conftest.a
   ln conftest.a conftest.b 2>&5 || hard_links=no
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
   if test "$hard_links" = no; then
-    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
@@ -17990,7 +16862,7 @@ else
   need_locks=no
 fi
 
-{ $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
 
   runpath_var=
@@ -18390,11 +17262,7 @@ _LT_EOF
        # -berok will link without error, but may produce a broken library.
        allow_undefined_flag_GCJ='-berok'
        # Determine the default libpath from the value encoded in an empty executable.
-       cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -18405,43 +17273,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
        hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -18453,11 +17294,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
          archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
        else
         # Determine the default libpath from the value encoded in an empty executable.
-        cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -18468,43 +17305,16 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+if ac_fn_c_try_link "$LINENO"; then :
 
 aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`
 # Check for a 64-bit object if we didn't find anything.
 if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0  *\(.*\)$/\1/; p; }
 }'`; fi
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
 
         hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath"
@@ -18952,7 +17762,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
     esac
   fi
 
-{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_GCJ" >&5
 $as_echo "$ld_shlibs_GCJ" >&6; }
 test "$ld_shlibs_GCJ" = no && can_build_shared=no
 
@@ -18973,16 +17783,16 @@ x|xyes)
       # Test whether the compiler implicitly links with -lc since on some
       # systems, -lgcc has to come before -lc. If gcc already passes -lc
       # to ld, don't add -lc before -lgcc.
-      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
       $rm conftest*
       printf "$lt_simple_compile_test_code" > conftest.$ac_ext
 
-      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+      if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } 2>conftest.err; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
         soname=conftest
         lib=conftest
         libobjs=conftest.$ac_objext
@@ -18996,11 +17806,11 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         libname=conftest
         lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ
         allow_undefined_flag_GCJ=
-        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5
+        if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5
   (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5
   ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
         then
          archive_cmds_need_lc_GCJ=no
         else
@@ -19011,7 +17821,7 @@ $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
         cat conftest.err 1>&5
       fi
       $rm conftest*
-      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_GCJ" >&5
 $as_echo "$archive_cmds_need_lc_GCJ" >&6; }
       ;;
     esac
@@ -19019,7 +17829,7 @@ $as_echo "$archive_cmds_need_lc_GCJ" >&6; }
   ;;
 esac
 
-{ $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
 $as_echo_n "checking dynamic linker characteristics... " >&6; }
 library_names_spec=
 libname_spec='lib$name'
@@ -19607,7 +18417,7 @@ uts4*)
   dynamic_linker=no
   ;;
 esac
-{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
 test "$dynamic_linker" = no && can_build_shared=no
 
@@ -19616,7 +18426,7 @@ if test "$GCC" = yes; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-{ $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
 $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action_GCJ=
 if test -n "$hardcode_libdir_flag_spec_GCJ" || \
@@ -19641,7 +18451,7 @@ else
   # directories.
   hardcode_action_GCJ=unsupported
 fi
-{ $as_echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_GCJ" >&5
 $as_echo "$hardcode_action_GCJ" >&6; }
 
 if test "$hardcode_action_GCJ" = relink; then
@@ -20553,9 +19363,7 @@ CC="$lt_save_CC"
        ;;
 
       *)
-       { { $as_echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5
-$as_echo "$as_me: error: Unsupported tag name: $tagname" >&2;}
-   { (exit 1); exit 1; }; }
+       as_fn_error "Unsupported tag name: $tagname" "$LINENO" 5
        ;;
       esac
 
@@ -20573,9 +19381,7 @@ $as_echo "$as_me: error: Unsupported tag name: $tagname" >&2;}
     chmod +x "$ofile"
   else
     rm -f "${ofile}T"
-    { { $as_echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5
-$as_echo "$as_me: error: unable to update list of available tagged configurations." >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "unable to update list of available tagged configurations." "$LINENO" 5
   fi
 fi
 
@@ -20608,10 +19414,10 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool'
 
 
 
-{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
 if test -z "$MKDIR_P"; then
-  if test "${ac_cv_path_mkdir+set}" = set; then
+  if test "${ac_cv_path_mkdir+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
@@ -20619,7 +19425,7 @@ for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_prog in mkdir gmkdir; do
+    for ac_prog in mkdir gmkdir; do
         for ac_exec_ext in '' $ac_executable_extensions; do
           { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
           case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
           esac
         done
        done
-done
+  done
 IFS=$as_save_IFS
 
 fi
 
+  test -d ./--version && rmdir ./--version
   if test "${ac_cv_path_mkdir+set}" = set; then
     MKDIR_P="$ac_cv_path_mkdir -p"
   else
     # value for MKDIR_P within a source directory, because that will
     # break other packages using the cache if that directory is
     # removed, or if the value is a relative name.
-    test -d ./--version && rmdir ./--version
     MKDIR_P="$ac_install_sh -d"
   fi
 fi
-{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
 $as_echo "$MKDIR_P" >&6; }
 
 
 # Check for library functions that SQLite can optionally use.
-
-
-
-
-
 for ac_func in fdatasync usleep fullfsync localtime_r gmtime_r
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* 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
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'` = yes; then
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+   if test "x$as_val" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
@@ -20756,188 +19471,37 @@ _ACEOF
 fi
 done
 
-{ $as_echo "$as_me:$LINENO: checking whether strerror_r is declared" >&5
-$as_echo_n "checking whether strerror_r is declared... " >&6; }
-if test "${ac_cv_have_decl_strerror_r+set}" = set; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_includes_default
-int
-main ()
-{
-#ifndef strerror_r
-  (void) strerror_r;
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
-  ac_cv_have_decl_strerror_r=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_cv_have_decl_strerror_r=no
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_have_decl_strerror_r" >&5
-$as_echo "$ac_cv_have_decl_strerror_r" >&6; }
-if test $ac_cv_have_decl_strerror_r = yes; then
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_STRERROR_R 1
-_ACEOF
-
-
+ac_fn_c_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default"
+if test "x$ac_cv_have_decl_strerror_r" = x""yes; then :
+  ac_have_decl=1
 else
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_STRERROR_R 0
-_ACEOF
-
-
+  ac_have_decl=0
 fi
 
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_STRERROR_R $ac_have_decl
+_ACEOF
 
-
-for ac_func in strerror_r
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* 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
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'` = yes; then
+for ac_func in strerror_r
+do :
+  ac_fn_c_check_func "$LINENO" "strerror_r" "ac_cv_func_strerror_r"
+if test "x$ac_cv_func_strerror_r" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_STRERROR_R 1
 _ACEOF
 
 fi
 done
 
-{ $as_echo "$as_me:$LINENO: checking whether strerror_r returns char *" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5
 $as_echo_n "checking whether strerror_r returns char *... " >&6; }
-if test "${ac_cv_func_strerror_r_char_p+set}" = set; then
+if test "${ac_cv_func_strerror_r_char_p+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
 
     ac_cv_func_strerror_r_char_p=no
     if test $ac_cv_have_decl_strerror_r = yes; then
-      cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
 int
@@ -20953,32 +19517,9 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_compile") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_func_strerror_r_char_p=yes
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     else
       # strerror_r is not declared.  Choose between
@@ -20987,14 +19528,10 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
       # former has a strerror_r that returns char*, while the latter
       # has a strerror_r that returns `int'.
       # This test should segfault on the DEC system.
-      if test "$cross_compiling" = yes; then
+      if test "$cross_compiling" = yes; then :
   :
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
        extern char *strerror_r ();
@@ -21008,50 +19545,21 @@ char buf[100];
   return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
-  { (case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+if ac_fn_c_try_run "$LINENO"; then :
   ac_cv_func_strerror_r_char_p=yes
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
 fi
-rm -rf conftest.dSYM
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-
     fi
 
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_strerror_r_char_p" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5
 $as_echo "$ac_cv_func_strerror_r_char_p" >&6; }
 if test $ac_cv_func_strerror_r_char_p = yes; then
 
-cat >>confdefs.h <<\_ACEOF
-#define STRERROR_R_CHAR_P 1
-_ACEOF
+$as_echo "#define STRERROR_R_CHAR_P 1" >>confdefs.h
 
 fi
 
@@ -21064,7 +19572,7 @@ ac_config_files="$ac_config_files Makefile sqlite3.pc"
 #   --enable-readline
 #
 # Check whether --enable-readline was given.
-if test "${enable_readline+set}" = set; then
+if test "${enable_readline+set}" = set; then :
   enableval=$enable_readline;
 else
   enable_readline=yes
 if test x"$enable_readline" != xno ; then
   sLIBS=$LIBS
   LIBS=""
-  { $as_echo "$as_me:$LINENO: checking for library containing tgetent" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
 $as_echo_n "checking for library containing tgetent... " >&6; }
-if test "${ac_cv_search_tgetent+set}" = set; then
+if test "${ac_cv_search_tgetent+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -21108,69 +19612,38 @@ for ac_lib in '' curses ncurses ncursesw; do
     ac_res=-l$ac_lib
     LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
   fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+  if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_tgetent=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_tgetent+set}" = set; then
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_tgetent+set}" = set; then :
   break
 fi
 done
-if test "${ac_cv_search_tgetent+set}" = set; then
-  :
+if test "${ac_cv_search_tgetent+set}" = set; then :
+
 else
   ac_cv_search_tgetent=no
 fi
 rm conftest.$ac_ext
 LIBS=$ac_func_search_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_tgetent" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
 $as_echo "$ac_cv_search_tgetent" >&6; }
 ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no; then
+if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
 fi
 
-  { $as_echo "$as_me:$LINENO: checking for library containing readline" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing readline" >&5
 $as_echo_n "checking for library containing readline... " >&6; }
-if test "${ac_cv_search_readline+set}" = set; then
+if test "${ac_cv_search_readline+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -21195,155 +19668,39 @@ for ac_lib in '' readline; do
     ac_res=-l$ac_lib
     LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
   fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+  if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_readline=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_readline+set}" = set; then
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_readline+set}" = set; then :
   break
 fi
 done
-if test "${ac_cv_search_readline+set}" = set; then
-  :
+if test "${ac_cv_search_readline+set}" = set; then :
+
 else
   ac_cv_search_readline=no
 fi
 rm conftest.$ac_ext
 LIBS=$ac_func_search_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_readline" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_readline" >&5
 $as_echo "$ac_cv_search_readline" >&6; }
 ac_res=$ac_cv_search_readline
-if test "$ac_res" != no; then
+if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
 else
   enable_readline=no
 fi
 
-
-for ac_func in readline
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* 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
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       eval "$as_ac_var=no"
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'` = yes; then
+  for ac_func in readline
+do :
+  ac_fn_c_check_func "$LINENO" "readline" "ac_cv_func_readline"
+if test "x$ac_cv_func_readline" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_READLINE 1
 _ACEOF
 
 fi
@@ -21359,7 +19716,7 @@ fi
 #   --enable-threadsafe
 #
 # Check whether --enable-threadsafe was given.
-if test "${enable_threadsafe+set}" = set; then
+if test "${enable_threadsafe+set}" = set; then :
   enableval=$enable_threadsafe;
 else
   enable_threadsafe=yes
 THREADSAFE_FLAGS=-DSQLITE_THREADSAFE=0
 if test x"$enable_threadsafe" != "xno"; then
   THREADSAFE_FLAGS="-D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
-  { $as_echo "$as_me:$LINENO: checking for library containing pthread_create" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5
 $as_echo_n "checking for library containing pthread_create... " >&6; }
-if test "${ac_cv_search_pthread_create+set}" = set; then
+if test "${ac_cv_search_pthread_create+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -21403,54 +19756,27 @@ for ac_lib in '' pthread; do
     ac_res=-l$ac_lib
     LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
   fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
+  if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_pthread_create=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
 fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_pthread_create+set}" = set; then
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_pthread_create+set}" = set; then :
   break
 fi
 done
-if test "${ac_cv_search_pthread_create+set}" = set; then
-  :
+if test "${ac_cv_search_pthread_create+set}" = set; then :
+
 else
   ac_cv_search_pthread_create=no
 fi
 rm conftest.$ac_ext
 LIBS=$ac_func_search_save_LIBS
 fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_pthread_create" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5
 $as_echo "$ac_cv_search_pthread_create" >&6; }
 ac_res=$ac_cv_search_pthread_create
-if test "$ac_res" != no; then
+if test "$ac_res" != no; then :
   test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
 fi
 #   --enable-dynamic-extensions
 #
 # Check whether --enable-dynamic-extensions was given.
-if test "${enable_dynamic_extensions+set}" = set; then
+if test "${enable_dynamic_extensions+set}" = set; then :
   enableval=$enable_dynamic_extensions;
 else
   enable_dynamic_extensions=yes
 fi
 
 if test x"$enable_dynamic_extensions" != "xno"; then
-  { $as_echo "$as_me:$LINENO: checking for library containing dlopen" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
 $as_echo_n "checking for library containing dlopen... " >&6; }
-if test "${ac_cv_search_dlopen+set}" = set; then
+if test "${ac_cv_search_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
   ac_func_search_save_LIBS=$LIBS
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 /* Override any GCC internal prototype to avoid an error.
@@ -21498,170 +19820,54 @@ return dlopen ();
   return 0;
 }
 _ACEOF
-for ac_lib in '' dl; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  ac_cv_search_dlopen=$ac_res
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext
-  if test "${ac_cv_search_dlopen+set}" = set; then
-  break
-fi
-done
-if test "${ac_cv_search_dlopen+set}" = set; then
-  :
-else
-  ac_cv_search_dlopen=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_dlopen" >&5
-$as_echo "$ac_cv_search_dlopen" >&6; }
-ac_res=$ac_cv_search_dlopen
-if test "$ac_res" != no; then
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
-  DYNAMIC_EXTENSION_FLAGS=-DSQLITE_OMIT_LOAD_EXTENSION=1
-fi
-{ $as_echo "$as_me:$LINENO: checking for whether to support dynamic extensions" >&5
-$as_echo_n "checking for whether to support dynamic extensions... " >&6; }
-{ $as_echo "$as_me:$LINENO: result: $enable_dynamic_extensions" >&5
-$as_echo "$enable_dynamic_extensions" >&6; }
-
-#-----------------------------------------------------------------------
-
-
-for ac_func in posix_fallocate
-do
-as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
-$as_echo_n "checking for $ac_func... " >&6; }
-if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $ac_func
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $ac_func ();
-/* 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
-#endif
-
-int
-main ()
-{
-return $ac_func ();
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
-$as_echo "$ac_try_echo") >&5
-  (eval "$ac_link") 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        $as_test_x conftest$ac_exeext
-       }; then
-  eval "$as_ac_var=yes"
+for ac_lib in '' dl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_dlopen=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if test "${ac_cv_search_dlopen+set}" = set; then :
+  break
+fi
+done
+if test "${ac_cv_search_dlopen+set}" = set; then :
+
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
+$as_echo "$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
 
-       eval "$as_ac_var=no"
 fi
 
-rm -rf conftest.dSYM
-rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
-      conftest$ac_exeext conftest.$ac_ext
+else
+  DYNAMIC_EXTENSION_FLAGS=-DSQLITE_OMIT_LOAD_EXTENSION=1
 fi
-ac_res=`eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'`
-              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-if test `eval 'as_val=${'$as_ac_var'}
-                $as_echo "$as_val"'` = yes; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for whether to support dynamic extensions" >&5
+$as_echo_n "checking for whether to support dynamic extensions... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_dynamic_extensions" >&5
+$as_echo "$enable_dynamic_extensions" >&6; }
+
+#-----------------------------------------------------------------------
+
+for ac_func in posix_fallocate
+do :
+  ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate"
+if test "x$ac_cv_func_posix_fallocate" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_POSIX_FALLOCATE 1
 _ACEOF
 
 fi
@@ -21720,13 +19926,13 @@ _ACEOF
     case $ac_val in #(
     *${as_nl}*)
       case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
-$as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
       esac
       case $ac_var in #(
       _ | IFS | as_nl) ;; #(
       BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) $as_unset $ac_var ;;
+      *) { eval $ac_var=; unset $ac_var;} ;;
       esac ;;
     esac
   done
@@ -21734,8 +19940,8 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
   (set) 2>&1 |
     case $as_nl`(ac_space=' '; set) 2>&1` in #(
     *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes (double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      # `set' does not quote correctly, so add quotesdouble-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
       sed -n \
        "s/'/'\\\\''/g;
          s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
@@ -21758,11 +19964,11 @@ $as_echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
 if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
   if test -w "$cache_file"; then
     test "x$cache_file" != "x/dev/null" &&
-      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
 $as_echo "$as_me: updating cache $cache_file" >&6;}
     cat confcache >$cache_file
   else
-    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
   fi
 fi
@@ -21818,8 +20024,8 @@ for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
   ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
   # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
   #    will be set to the directory where LIBOBJS objects are built.
-  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
-  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
 done
 LIBOBJS=$ac_libobjs
 
@@ -21827,41 +20033,30 @@ LTLIBOBJS=$ac_ltlibobjs
 
 
 if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
-  { { $as_echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-$as_echo "$as_me: error: conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
-  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-$as_echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
-  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-$as_echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
-  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&5
-$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
-Usually this means the macro was only invoked conditionally." >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 
 : ${CONFIG_STATUS=./config.status}
 ac_write_fail=0
 ac_clean_files_save=$ac_clean_files
 ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
-cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
 #! $SHELL
 # Generated by $as_me.
 # Run this file to recreate the current configuration.
@@ -21871,17 +20066,18 @@ cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 debug=false
 ac_cs_recheck=false
 ac_cs_silent=false
-SHELL=\${CONFIG_SHELL-$SHELL}
-_ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
 
 # Be more Bourne compatible
 DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
   # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
@@ -21889,23 +20085,15 @@ if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in
-  *posix*) set -o posix ;;
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
 esac
-
 fi
 
 
-
-
-# PATH needs CR
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
 as_nl='
 '
 export as_nl
@@ -21913,7 +20101,13 @@ export as_nl
 as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
 as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
   as_echo='printf %s\n'
   as_echo_n='printf %s'
 else
@@ -21924,7 +20118,7 @@ else
     as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
     as_echo_n_body='eval
       arg=$1;
-      case $arg in
+      case $arg in #(
       *"$as_nl"*)
        expr "X$arg" : "X\\(.*\\)$as_nl";
        arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
@@ -21947,13 +20141,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
   }
 fi
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
-else
-  as_unset=false
-fi
-
 
 # IFS
 # We need space, tab and new line, in precisely that order.  Quoting is
 IFS=" ""       $as_nl"
 
 # Find who we are.  Look in the path if we contain no directory separator.
-case $0 in
+case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
   *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
 IFS=$as_save_IFS
 
      ;;
@@ -21983,12 +20170,16 @@ if test "x$as_myself" = x; then
 fi
 if test ! -f "$as_myself"; then
   $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  { (exit 1); exit 1; }
+  exit 1
 fi
 
-# Work around bugs in pre-3.0 UWIN ksh.
-for as_var in ENV MAIL MAILPATH
-do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
 done
 PS1='$ '
 PS2='> '
@@ -22000,7 +20191,89 @@ export LC_ALL
 LANGUAGE=C
 export LANGUAGE
 
-# Required to use basename.
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
 if expr a : '\(a\)' >/dev/null 2>&1 &&
    test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
@@ -22014,8 +20287,12 @@ else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
 as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
         X"$0" : 'X\(//\)$' \| \
@@ -22035,76 +20312,25 @@ $as_echo X/"$0" |
          }
          s/.*/./; q'`
 
-# CDPATH.
-$as_unset CDPATH
-
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line after each line using $LINENO; the second 'sed'
-  # does the real work.  The second script uses 'N' to pair each
-  # line-number line with the line containing $LINENO, and appends
-  # trailing '-' during substitution so that $LINENO is not a special
-  # case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # scripts with optimization help from Paolo Bonzini.  Blame Lee
-  # E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
 
 ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in
+case `echo -n x` in #(((((
 -n*)
-  case `echo 'x\c'` in
+  case `echo 'xy\c'` in
   *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  *)   ECHO_C='\c';;
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
   esac;;
 *)
   ECHO_N='-n';;
 esac
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
 
 rm -f conf$$ conf$$.exe conf$$.file
 if test -d conf$$.dir; then
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
 
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
 if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
+  as_mkdir_p='mkdir -p "$as_dir"'
 else
   test -d ./-p && rmdir ./-p
   as_mkdir_p=false
@@ -22153,10 +20427,10 @@ else
       if test -d "$1"; then
        test -d "$1/.";
       else
-       case $1 in
+       case $1 in #(
        -*)set "./$1";;
        esac;
-       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
        ???[sx]*):;;*)false;;esac;fi
     '\'' sh
   '
@@ -22171,13 +20445,19 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
 exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
 
-# Save the log message, to keep $[0] and so on meaningful, and to
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by sqlite $as_me 3.7.6.2, which was
-generated by GNU Autoconf 2.62.  Invocation command line was
+This file was extended by sqlite $as_me 3.7.7.1, which was
+generated by GNU Autoconf 2.65.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -22190,6 +20470,12 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q`
 
 _ACEOF
 
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 # Files that config.status was made for.
 config_files="$ac_config_files"
@@ -22199,17 +20485,20 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 ac_cs_usage="\
-\`$as_me' instantiates files from templates according to the
-current configuration.
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
 
-Usage: $0 [OPTIONS] [FILE]...
+Usage: $0 [OPTION]... [TAG]...
 
   -h, --help       print this help, then exit
   -V, --version    print version number and configuration settings, then exit
-  -q, --quiet      do not print progress messages
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
   -d, --debug      don't remove temporary files
       --recheck    update $as_me by reconfiguring in the same conditions
-  --file=FILE[:TEMPLATE]
+      --file=FILE[:TEMPLATE]
                    instantiate the configuration file FILE
 
 Configuration files:
@@ -22218,16 +20507,17 @@ $config_files
 Configuration commands:
 $config_commands
 
-Report bugs to <bug-autoconf@gnu.org>."
+Report bugs to <http://www.sqlite.org>."
 
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-sqlite config.status 3.7.6.2
-configured by $0, generated by GNU Autoconf 2.62,
-  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+sqlite config.status 3.7.7.1
+configured by $0, generated by GNU Autoconf 2.65,
+  with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2008 Free Software Foundation, Inc.
+Copyright (C) 2009 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -22263,6 +20553,8 @@ do
     ac_cs_recheck=: ;;
   --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
     $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
   --debug | --debu | --deb | --de | --d | -d )
     debug=: ;;
   --file | --fil | --fi | --f )
@@ -22270,7 +20562,7 @@ do
     case $ac_optarg in
     *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
     esac
-    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
     ac_need_defaults=false;;
   --he | --h |  --help | --hel | -h )
     $as_echo "$ac_cs_usage"; exit ;;
     ac_cs_silent=: ;;
 
   # This is an error.
-  -*) { $as_echo "$as_me: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; } ;;
+  -*) as_fn_error "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
 
-  *) ac_config_targets="$ac_config_targets $1"
+  *) as_fn_append ac_config_targets " $1"
      ac_need_defaults=false ;;
 
   esac
@@ -22338,9 +20629,7 @@ do
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "sqlite3.pc") CONFIG_FILES="$CONFIG_FILES sqlite3.pc" ;;
 
-  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
-$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
-   { (exit 1); exit 1; }; };;
+  *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
 done
 
@@ -22366,7 +20655,7 @@ $debug ||
   trap 'exit_status=$?
   { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
 ' 0
-  trap '{ (exit 1); exit 1; }' 1 2 13 15
+  trap 'as_fn_exit 1' 1 2 13 15
 }
 # Create a (secure) tmp directory for tmp files.
 
@@ -22377,11 +20666,7 @@ $debug ||
 {
   tmp=./conf$$-$RANDOM
   (umask 077 && mkdir "$tmp")
-} ||
-{
-   $as_echo "$as_me: cannot create a temporary directory in ." >&2
-   { (exit 1); exit 1; }
-}
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
 
 # Set up the scripts for CONFIG_FILES section.
 # No need to generate them if there are no CONFIG_FILES.
@@ -22389,10 +20674,16 @@ $debug ||
 if test -n "$CONFIG_FILES"; then
 
 
-ac_cr='\r'
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
 ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
 if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
-  ac_cs_awk_cr='\\r'
+  ac_cs_awk_cr='\r'
 else
   ac_cs_awk_cr=$ac_cr
 fi
@@ -22406,23 +20697,18 @@ _ACEOF
   echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
   echo "_ACEOF"
 } >conf$$subs.sh ||
-  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
 ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   . ./conf$$subs.sh ||
-    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` = $ac_delim_num; then
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
     break
   elif $ac_last_try; then
-    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
   else
     ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
   fi
@@ -22444,7 +20730,7 @@ s/'"$ac_delim"'$//
 t delim
 :nl
 h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
 t more1
 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
 p
@@ -22458,7 +20744,7 @@ s/.\{148\}//
 t nl
 :delim
 h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
 t more2
 s/["\\]/\\&/g; s/^/"/; s/$/"/
 p
@@ -22511,9 +20797,7 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
 else
   cat
 fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
-  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
-$as_echo "$as_me: error: could not setup config files machinery" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error "could not setup config files machinery" "$LINENO" 5
 _ACEOF
 
 # VPATH may cause trouble with some makes, so we remove $(srcdir),
@@ -22544,9 +20828,7 @@ do
   esac
   case $ac_mode$ac_tag in
   :[FHL]*:*);;
-  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
-$as_echo "$as_me: error: Invalid tag $ac_tag." >&2;}
-   { (exit 1); exit 1; }; };;
+  :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
   :[FH]-) ac_tag=-:-;;
   :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
   esac
@@ -22574,12 +20856,10 @@ $as_echo "$as_me: error: Invalid tag $ac_tag." >&2;}
           [\\/$]*) false;;
           *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
           esac ||
-          { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
-$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
-   { (exit 1); exit 1; }; };;
+          as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
       esac
       case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
-      ac_file_inputs="$ac_file_inputs '$ac_f'"
+      as_fn_append ac_file_inputs " '$ac_f'"
     done
 
     # Let's still pretend it is `configure' which instantiates (i.e., don't
@@ -22590,7 +20870,7 @@ $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
        `' by configure.'
     if test x"$ac_file" != x-; then
       configure_input="$ac_file.  $configure_input"
-      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
 $as_echo "$as_me: creating $ac_file" >&6;}
     fi
     # Neutralize special characters interpreted by sed in replacement strings.
@@ -22603,9 +20883,7 @@ $as_echo "$as_me: creating $ac_file" >&6;}
 
     case $ac_tag in
     *:-:* | *:-) cat >"$tmp/stdin" \
-      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; } ;;
+      || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
     esac
     ;;
   esac
@@ -22633,47 +20911,7 @@ $as_echo X"$ac_file" |
            q
          }
          s/.*/./; q'`
-  { as_dir="$ac_dir"
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
-$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
-   { (exit 1); exit 1; }; }; }
+  as_dir="$ac_dir"; as_fn_mkdir_p
   ac_builddir=.
 
 case "$ac_dir" in
@@ -22730,7 +20968,6 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # If the template does not know about datarootdir, expand it.
 # FIXME: This hack should be removed a few years after 2.60.
 ac_datarootdir_hack=; ac_datarootdir_seen=
-
 ac_sed_dataroot='
 /datarootdir/ {
   p
@@ -22740,12 +20977,11 @@ ac_sed_dataroot='
 /@docdir@/p
 /@infodir@/p
 /@localedir@/p
-/@mandir@/p
-'
+/@mandir@/p'
 case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
 *datarootdir*) ac_datarootdir_seen=yes;;
 *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
@@ -22755,7 +20991,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
   s&@infodir@&$infodir&g
   s&@localedir@&$localedir&g
   s&@mandir@&$mandir&g
-    s&\\\${datarootdir}&$datarootdir&g' ;;
+  s&\\\${datarootdir}&$datarootdir&g' ;;
 esac
 _ACEOF
 
@@ -22784,14 +21020,12 @@ s&@MKDIR_P@&$ac_MKDIR_P&;t t
 $ac_datarootdir_hack
 "
 eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
-  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
 
 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
   { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
   { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
-  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
 which seems to be undefined.  Please make sure it is defined." >&5
 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
 which seems to be undefined.  Please make sure it is defined." >&2;}
@@ -22801,13 +21035,11 @@ which seems to be undefined.  Please make sure it is defined." >&2;}
   -) cat "$tmp/out" && rm -f "$tmp/out";;
   *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
   esac \
-  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
-$as_echo "$as_me: error: could not create $ac_file" >&2;}
-   { (exit 1); exit 1; }; }
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
  ;;
 
 
-  :C)  { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
 $as_echo "$as_me: executing $ac_file commands" >&6;}
  ;;
   esac
@@ -22891,47 +21123,7 @@ $as_echo X"$file" |
            q
          }
          s/.*/./; q'`
-    { as_dir=$dirpart/$fdir
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
-$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
-   { (exit 1); exit 1; }; }; }
+    as_dir=$dirpart/$fdir; as_fn_mkdir_p
     # echo "creating $dirpart/$file"
     echo '# dummy' > "$dirpart/$file"
   done
@@ -22942,15 +21134,12 @@ done
 done # for ac_tag
 
 
-{ (exit 0); exit 0; }
+as_fn_exit 0
 _ACEOF
-chmod +x $CONFIG_STATUS
 ac_clean_files=$ac_clean_files_save
 
 test $ac_write_fail = 0 ||
-  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
 
 
 # configure is writing to config.log, and then calls config.status.
@@ -22971,10 +21160,10 @@ if test "$no_create" != yes; then
   exec 5>>config.log
   # Use ||, not &&, to avoid exiting from the if with $? = 1, which
   # would make configure fail if this is the last instruction.
-  $ac_cs_success || { (exit 1); exit 1; }
+  $ac_cs_success || as_fn_exit $?
 fi
 if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
-  { $as_echo "$as_me:$LINENO: WARNING: Unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: Unrecognized options: $ac_unrecognized_opts" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
 fi
 
index e04befd1f722546707c95ceb6176cca0504c1acd..08482deb20df61d0385325f42249874f5e1d0cba 100644 (file)
@@ -8,7 +8,7 @@
 #
 
 AC_PREREQ(2.61)
-AC_INIT(sqlite, 3.7.6.2, http://www.sqlite.org)
+AC_INIT(sqlite, 3.7.7.1, http://www.sqlite.org)
 AC_CONFIG_SRCDIR([sqlite3.c])
 
 # Use automake.
index aab70b29db45a244fe78bd11101f6902e8b235ba..a54c922e87a34b873d8c22ce722ff004619484c5 100644 (file)
@@ -2302,6 +2302,11 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     enableTimer = booleanValue(azArg[1]);
   }else
   
+  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
+    printf("SQLite %s %s\n",
+        sqlite3_libversion(), sqlite3_sourceid());
+  }else
+
   if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
     int j;
     assert( nArg<=ArraySize(azArg) );
@@ -2649,6 +2654,7 @@ static void main_init(struct callback_data *data) {
   data->mode = MODE_List;
   memcpy(data->separator,"|", 2);
   data->showHeader = 0;
+  sqlite3_config(SQLITE_CONFIG_URI, 1);
   sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
   sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
   sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
@@ -2663,6 +2669,11 @@ int main(int argc, char **argv){
   int i;
   int rc = 0;
 
+  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
+    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
+            sqlite3_sourceid(), SQLITE_SOURCE_ID);
+    exit(1);
+  }
   Argv0 = argv[0];
   main_init(&data);
   stdin_is_interactive = isatty(0);
@@ -2830,7 +2841,7 @@ int main(int argc, char **argv){
     }else if( strcmp(z,"-bail")==0 ){
       bail_on_error = 1;
     }else if( strcmp(z,"-version")==0 ){
-      printf("%s\n", sqlite3_libversion());
+      printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
       return 0;
     }else if( strcmp(z,"-interactive")==0 ){
       stdin_is_interactive = 1;
@@ -2875,10 +2886,10 @@ int main(int argc, char **argv){
       char *zHistory = 0;
       int nHistory;
       printf(
-        "SQLite version %s\n"
+        "SQLite version %s %.19s\n"
         "Enter \".help\" for instructions\n"
         "Enter SQL statements terminated with a \";\"\n",
-        sqlite3_libversion()
+        sqlite3_libversion(), sqlite3_sourceid()
       );
       zHome = find_home_dir();
       if( zHome ){
index 55f058c26d2fc241656a002e4a26e51aef8e098c..2c426c21ebd47b4a2c342912ece913f3e368da4c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.7.6.2.  By combining all the individual C code files into this 
+** version 3.7.7.1.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
@@ -650,9 +650,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.6.2"
-#define SQLITE_VERSION_NUMBER 3007006
-#define SQLITE_SOURCE_ID      "2011-04-17 17:25:17 154ddbc17120be2915eb03edc52af1225eb7cb5e"
+#define SQLITE_VERSION        "3.7.7.1"
+#define SQLITE_VERSION_NUMBER 3007007
+#define SQLITE_SOURCE_ID      "2011-06-28 17:39:05 af0d91adf497f5f36ec3813f04235a6e195a605f"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -853,7 +853,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
 ** argument.  ^If the callback function of the 3rd argument to
 ** sqlite3_exec() is not NULL, then it is invoked for each result row
 ** coming out of the evaluated SQL statements.  ^The 4th argument to
-** to sqlite3_exec() is relayed through to the 1st argument of each
+** sqlite3_exec() is relayed through to the 1st argument of each
 ** callback invocation.  ^If the callback pointer to sqlite3_exec()
 ** is NULL, then no callback is ever invoked and result rows are
 ** ignored.
@@ -918,7 +918,8 @@ SQLITE_API int sqlite3_exec(
 **
 ** New error codes may be added in future versions of SQLite.
 **
-** See also: [SQLITE_IOERR_READ | extended result codes]
+** See also: [SQLITE_IOERR_READ | extended result codes],
+** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
 */
 #define SQLITE_OK           0   /* Successful result */
 /* beginning-of-error-codes */
@@ -995,17 +996,21 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_IOERR_SHMOPEN           (SQLITE_IOERR | (18<<8))
 #define SQLITE_IOERR_SHMSIZE           (SQLITE_IOERR | (19<<8))
 #define SQLITE_IOERR_SHMLOCK           (SQLITE_IOERR | (20<<8))
+#define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
+#define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
+#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
+#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
+#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
 
 /*
 ** CAPI3REF: Flags For File Open Operations
 **
 ** These bit values are intended for use in the
 ** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
+** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
 */
 #define SQLITE_OPEN_READONLY         0x00000001  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_READWRITE        0x00000002  /* Ok for sqlite3_open_v2() */
@@ -1013,6 +1018,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_OPEN_DELETEONCLOSE    0x00000008  /* VFS only */
 #define SQLITE_OPEN_EXCLUSIVE        0x00000010  /* VFS only */
 #define SQLITE_OPEN_AUTOPROXY        0x00000020  /* VFS only */
+#define SQLITE_OPEN_URI              0x00000040  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_MAIN_DB          0x00000100  /* VFS only */
 #define SQLITE_OPEN_TEMP_DB          0x00000200  /* VFS only */
 #define SQLITE_OPEN_TRANSIENT_DB     0x00000400  /* VFS only */
@@ -1123,17 +1129,18 @@ struct sqlite3_file {
 /*
 ** CAPI3REF: OS Interface File Virtual Methods Object
 **
-** Every file opened by the [sqlite3_vfs] xOpen method populates an
+** Every file opened by the [sqlite3_vfs.xOpen] method populates an
 ** [sqlite3_file] object (or, more commonly, a subclass of the
 ** [sqlite3_file] object) with a pointer to an instance of this object.
 ** This object defines the methods used to perform various operations
 ** against the open file represented by the [sqlite3_file] object.
 **
-** If the xOpen method sets the sqlite3_file.pMethods element 
+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element 
 ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
-** may be invoked even if the xOpen reported that it failed.  The
-** only way to prevent a call to xClose following a failed xOpen
-** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
+** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed.  The
+** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
+** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element
+** to NULL.
 **
 ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
 ** [SQLITE_SYNC_FULL].  The first choice is the normal fsync().
@@ -1305,7 +1312,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 **
 ** An instance of the sqlite3_vfs object defines the interface between
 ** the SQLite core and the underlying operating system.  The "vfs"
-** in the name of the object stands for "virtual file system".
+** in the name of the object stands for "virtual file system".  See
+** the [VFS | VFS documentation] for further information.
 **
 ** The value of the iVersion field is initially 1 but may be larger in
 ** future versions of SQLite.  Additional fields may be appended to this
@@ -1334,6 +1342,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** The zName field holds the name of the VFS module.  The name must
 ** be unique across all VFS modules.
 **
+** [[sqlite3_vfs.xOpen]]
 ** ^SQLite guarantees that the zFilename parameter to xOpen
 ** is either a NULL pointer or string obtained
 ** from xFullPathname() with an optional suffix added.
@@ -1411,6 +1420,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** element will be valid after xOpen returns regardless of the success
 ** or failure of the xOpen call.
 **
+** [[sqlite3_vfs.xAccess]]
 ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
 ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
 ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
@@ -1435,7 +1445,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** method returns a Julian Day Number for the current date and time as
 ** a floating point value.
 ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
-** Day Number multipled by 86400000 (the number of milliseconds in 
+** Day Number multiplied by 86400000 (the number of milliseconds in 
 ** a 24-hour day).  
 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
 ** date and time if that method is available (if iVersion is 2 or 
@@ -1657,9 +1667,9 @@ SQLITE_API int sqlite3_os_end(void);
 ** implementation of an application-defined [sqlite3_os_init()].
 **
 ** The first argument to sqlite3_config() is an integer
-** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines
+** [configuration option] that determines
 ** what property of SQLite is to be configured.  Subsequent arguments
-** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option]
+** vary depending on the [configuration option]
 ** in the first argument.
 **
 ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
@@ -1769,6 +1779,7 @@ struct sqlite3_mem_methods {
 
 /*
 ** CAPI3REF: Configuration Options
+** KEYWORDS: {configuration option}
 **
 ** These constants are the available integer configuration options that
 ** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1781,7 +1792,7 @@ struct sqlite3_mem_methods {
 ** is invoked.
 **
 ** <dl>
-** <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
+** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Single-thread.  In other words, it disables
 ** all mutexing and puts SQLite into a mode where it can only be used
@@ -1792,7 +1803,7 @@ struct sqlite3_mem_methods {
 ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
 ** configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_MULTITHREAD</dt>
+** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Multi-thread.  In other words, it disables
 ** mutexing on [database connection] and [prepared statement] objects.
@@ -1806,7 +1817,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
 ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_SERIALIZED</dt>
+** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Serialized. In other words, this option enables
 ** all mutexes including the recursive
@@ -1822,7 +1833,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
 ** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_MALLOC</dt>
+** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mem_methods] structure.  The argument specifies
 ** alternative low-level memory allocation routines to be used in place of
@@ -1830,7 +1841,7 @@ struct sqlite3_mem_methods {
 ** its own private copy of the content of the [sqlite3_mem_methods] structure
 ** before the [sqlite3_config()] call returns.</dd>
 **
-** <dt>SQLITE_CONFIG_GETMALLOC</dt>
+** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mem_methods] structure.  The [sqlite3_mem_methods]
 ** structure is filled with the currently defined memory allocation routines.)^
@@ -1838,7 +1849,7 @@ struct sqlite3_mem_methods {
 ** routines with a wrapper that simulations memory allocation failure or
 ** tracks memory usage, for example. </dd>
 **
-** <dt>SQLITE_CONFIG_MEMSTATUS</dt>
+** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
 ** <dd> ^This option takes single argument of type int, interpreted as a 
 ** boolean, which enables or disables the collection of memory allocation 
 ** statistics. ^(When memory allocation statistics are disabled, the 
@@ -1854,7 +1865,7 @@ struct sqlite3_mem_methods {
 ** allocation statistics are disabled by default.
 ** </dd>
 **
-** <dt>SQLITE_CONFIG_SCRATCH</dt>
+** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite can use for
 ** scratch memory.  There are three arguments:  A pointer an 8-byte
 ** aligned memory buffer from which the scratch allocations will be
@@ -1870,9 +1881,9 @@ struct sqlite3_mem_methods {
 ** scratch memory beyond what is provided by this configuration option, then 
 ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
 **
-** <dt>SQLITE_CONFIG_PAGECACHE</dt>
+** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implemenation.  
+** the database page cache with the default page cache implementation.  
 ** This configuration should not be used if an application-define page
 ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
 ** There are three arguments to this option: A pointer to 8-byte aligned
@@ -1891,7 +1902,7 @@ struct sqlite3_mem_methods {
 ** be aligned to an 8-byte boundary or subsequent behavior of SQLite
 ** will be undefined.</dd>
 **
-** <dt>SQLITE_CONFIG_HEAP</dt>
+** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite will use
 ** for all of its dynamic memory allocation needs beyond those provided
 ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
@@ -1908,7 +1919,7 @@ struct sqlite3_mem_methods {
 ** The minimum allocation size is capped at 2^12. Reasonable values
 ** for the minimum allocation size are 2^5 through 2^8.</dd>
 **
-** <dt>SQLITE_CONFIG_MUTEX</dt>
+** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mutex_methods] structure.  The argument specifies
 ** alternative low-level mutex routines to be used in place
@@ -1920,7 +1931,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
 ** return [SQLITE_ERROR].</dd>
 **
-** <dt>SQLITE_CONFIG_GETMUTEX</dt>
+** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mutex_methods] structure.  The
 ** [sqlite3_mutex_methods]
@@ -1933,7 +1944,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
 ** return [SQLITE_ERROR].</dd>
 **
-** <dt>SQLITE_CONFIG_LOOKASIDE</dt>
+** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
 ** <dd> ^(This option takes two arguments that determine the default
 ** memory allocation for the lookaside memory allocator on each
 ** [database connection].  The first argument is the
@@ -1943,18 +1954,18 @@ struct sqlite3_mem_methods {
 ** verb to [sqlite3_db_config()] can be used to change the lookaside
 ** configuration on individual connections.)^ </dd>
 **
-** <dt>SQLITE_CONFIG_PCACHE</dt>
+** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to
 ** an [sqlite3_pcache_methods] object.  This object specifies the interface
 ** to a custom page cache implementation.)^  ^SQLite makes a copy of the
 ** object and uses it for page cache memory allocations.</dd>
 **
-** <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** [sqlite3_pcache_methods] object.  SQLite copies of the current
 ** page cache implementation into that object.)^ </dd>
 **
-** <dt>SQLITE_CONFIG_LOG</dt>
+** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
 ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
 ** function with a call signature of void(*)(void*,int,const char*), 
 ** and a pointer to void. ^If the function pointer is not NULL, it is
@@ -1972,6 +1983,18 @@ struct sqlite3_mem_methods {
 ** In a multi-threaded application, the application-defined logger
 ** function must be threadsafe. </dd>
 **
+** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
+** <dd> This option takes a single argument of type int. If non-zero, then
+** URI handling is globally enabled. If the parameter is zero, then URI handling
+** is globally disabled. If URI handling is globally enabled, all filenames
+** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** specified as part of [ATTACH] commands are interpreted as URIs, regardless
+** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
+** connection is opened. If it is globally disabled, filenames are
+** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
+** database connection is opened. By default, URI handling is globally
+** disabled. The default value may be changed by compiling with the
+** [SQLITE_USE_URI] symbol defined.
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1990,6 +2013,7 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_PCACHE       14  /* sqlite3_pcache_methods* */
 #define SQLITE_CONFIG_GETPCACHE    15  /* sqlite3_pcache_methods* */
 #define SQLITE_CONFIG_LOG          16  /* xFunc, void* */
+#define SQLITE_CONFIG_URI          17  /* int */
 
 /*
 ** CAPI3REF: Database Connection Configuration Options
@@ -2075,13 +2099,17 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
 **
 ** ^This routine returns the [rowid] of the most recent
 ** successful [INSERT] into the database from the [database connection]
-** in the first argument.  ^If no successful [INSERT]s
+** in the first argument.  ^As of SQLite version 3.7.7, this routines
+** records the last insert rowid of both ordinary tables and [virtual tables].
+** ^If no successful [INSERT]s
 ** have ever occurred on that database connection, zero is returned.
 **
-** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted
-** row is returned by this routine as long as the trigger is running.
-** But once the trigger terminates, the value returned by this routine
-** reverts to the last value inserted before the trigger fired.)^
+** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
+** method, then this routine will return the [rowid] of the inserted
+** row as long as the trigger or virtual table method is running.
+** But once the trigger or virtual table method ends, the value returned 
+** by this routine reverts to what it was before the trigger or virtual
+** table method began.)^
 **
 ** ^An [INSERT] that fails due to a constraint violation is not a
 ** successful [INSERT] and does not change the value returned by this
@@ -2744,6 +2772,9 @@ SQLITE_API int sqlite3_set_authorizer(
 ** to signal SQLite whether or not the action is permitted.  See the
 ** [sqlite3_set_authorizer | authorizer documentation] for additional
 ** information.
+**
+** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
+** from the [sqlite3_vtab_on_conflict()] interface.
 */
 #define SQLITE_DENY   1   /* Abort the SQL statement with an error */
 #define SQLITE_IGNORE 2   /* Don't allow access, but don't generate an error */
@@ -2866,7 +2897,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 /*
 ** CAPI3REF: Opening A New Database Connection
 **
-** ^These routines open an SQLite database file whose name is given by the
+** ^These routines open an SQLite database file as specified by the 
 ** filename argument. ^The filename argument is interpreted as UTF-8 for
 ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
 ** order for sqlite3_open16(). ^(A [database connection] handle is usually
@@ -2893,7 +2924,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** sqlite3_open_v2() can take one of
 ** the following three values, optionally combined with the 
 ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^
+** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
 **
 ** <dl>
 ** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
@@ -2912,9 +2943,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** </dl>
 **
 ** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above or one of the combinations shown above combined
-** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
+** combinations shown above optionally combined with other
+** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
 ** then the behavior is undefined.
 **
 ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2929,6 +2959,11 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
 ** participate in [shared cache mode] even if it is enabled.
 **
+** ^The fourth parameter to sqlite3_open_v2() is the name of the
+** [sqlite3_vfs] object that defines the operating system interface that
+** the new database connection should use.  ^If the fourth parameter is
+** a NULL pointer then the default [sqlite3_vfs] object is used.
+**
 ** ^If the filename is ":memory:", then a private, temporary in-memory database
 ** is created for the connection.  ^This in-memory database will vanish when
 ** the database connection is closed.  Future versions of SQLite might
@@ -2941,10 +2976,111 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** on-disk database will be created.  ^This private database will be
 ** automatically deleted as soon as the database connection is closed.
 **
-** ^The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system interface that
-** the new database connection should use.  ^If the fourth parameter is
-** a NULL pointer then the default [sqlite3_vfs] object is used.
+** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3>
+**
+** ^If [URI filename] interpretation is enabled, and the filename argument
+** begins with "file:", then the filename is interpreted as a URI. ^URI
+** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
+** set in the fourth argument to sqlite3_open_v2(), or if it has
+** been enabled globally using the [SQLITE_CONFIG_URI] option with the
+** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
+** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** by default, but future releases of SQLite might enable URI filename
+** interpretation by default.  See "[URI filenames]" for additional
+** information.
+**
+** URI filenames are parsed according to RFC 3986. ^If the URI contains an
+** authority, then it must be either an empty string or the string 
+** "localhost". ^If the authority is not an empty string or "localhost", an 
+** error is returned to the caller. ^The fragment component of a URI, if 
+** present, is ignored.
+**
+** ^SQLite uses the path component of the URI as the name of the disk file
+** which contains the database. ^If the path begins with a '/' character, 
+** then it is interpreted as an absolute path. ^If the path does not begin 
+** with a '/' (meaning that the authority section is omitted from the URI)
+** then the path is interpreted as a relative path. 
+** ^On windows, the first component of an absolute path 
+** is a drive specification (e.g. "C:").
+**
+** [[core URI query parameters]]
+** The query component of a URI may contain parameters that are interpreted
+** either by SQLite itself, or by a [VFS | custom VFS implementation].
+** SQLite interprets the following three query parameters:
+**
+** <ul>
+**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
+**     a VFS object that provides the operating system interface that should
+**     be used to access the database file on disk. ^If this option is set to
+**     an empty string the default VFS object is used. ^Specifying an unknown
+**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
+**     present, then the VFS specified by the option takes precedence over
+**     the value passed as the fourth parameter to sqlite3_open_v2().
+**
+**   <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or
+**     "rwc". Attempting to set it to any other value is an error)^. 
+**     ^If "ro" is specified, then the database is opened for read-only 
+**     access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the 
+**     third argument to sqlite3_prepare_v2(). ^If the mode option is set to 
+**     "rw", then the database is opened for read-write (but not create) 
+**     access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had 
+**     been set. ^Value "rwc" is equivalent to setting both 
+**     SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is 
+**     used, it is an error to specify a value for the mode parameter that is 
+**     less restrictive than that specified by the flags passed as the third 
+**     parameter.
+**
+**   <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
+**     "private". ^Setting it to "shared" is equivalent to setting the
+**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
+**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
+**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
+**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
+**     a URI filename, its value overrides any behaviour requested by setting
+**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
+** </ul>
+**
+** ^Specifying an unknown parameter in the query component of a URI is not an
+** error.  Future versions of SQLite might understand additional query
+** parameters.  See "[query parameters with special meaning to SQLite]" for
+** additional information.
+**
+** [[URI filename examples]] <h3>URI filename examples</h3>
+**
+** <table border="1" align=center cellpadding=5>
+** <tr><th> URI filenames <th> Results
+** <tr><td> file:data.db <td> 
+**          Open the file "data.db" in the current directory.
+** <tr><td> file:/home/fred/data.db<br>
+**          file:///home/fred/data.db <br> 
+**          file://localhost/home/fred/data.db <br> <td> 
+**          Open the database file "/home/fred/data.db".
+** <tr><td> file://darkstar/home/fred/data.db <td> 
+**          An error. "darkstar" is not a recognized authority.
+** <tr><td style="white-space:nowrap"> 
+**          file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
+**     <td> Windows only: Open the file "data.db" on fred's desktop on drive
+**          C:. Note that the %20 escaping in this example is not strictly 
+**          necessary - space characters can be used literally
+**          in URI filenames.
+** <tr><td> file:data.db?mode=ro&cache=private <td> 
+**          Open file "data.db" in the current directory for read-only access.
+**          Regardless of whether or not shared-cache mode is enabled by
+**          default, use a private cache.
+** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
+**          Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
+** <tr><td> file:data.db?mode=readonly <td> 
+**          An error. "readonly" is not a valid option for the "mode" parameter.
+** </table>
+**
+** ^URI hexadecimal escape sequences (%HH) are supported within the path and
+** query components of a URI. A hexadecimal escape sequence consists of a
+** percent sign - "%" - followed by exactly two hexadecimal digits 
+** specifying an octet value. ^Before the path or query components of a
+** URI filename are interpreted, they are encoded using UTF-8 and all 
+** hexadecimal escape sequences replaced by a single byte containing the
+** corresponding octet. If this process generates an invalid UTF-8 encoding,
+** the results are undefined.
 **
 ** <b>Note to Windows users:</b>  The encoding used for the filename argument
 ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
@@ -2967,6 +3103,26 @@ SQLITE_API int sqlite3_open_v2(
   const char *zVfs        /* Name of VFS module to use */
 );
 
+/*
+** CAPI3REF: Obtain Values For URI Parameters
+**
+** This is a utility routine, useful to VFS implementations, that checks
+** to see if a database file was a URI that contained a specific query 
+** parameter, and if so obtains the value of the query parameter.
+**
+** The zFilename argument is the filename pointer passed into the xOpen()
+** method of a VFS implementation.  The zParam argument is the name of the
+** query parameter we seek.  This routine returns the value of the zParam
+** parameter if it exists.  If the parameter does not exist, this routine
+** returns a NULL pointer.
+**
+** If the zFilename argument to this function is not a pointer that SQLite
+** passed into the xOpen VFS method, then the behavior of this routine
+** is undefined and probably undesirable.
+*/
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+
+
 /*
 ** CAPI3REF: Error Codes And Messages
 **
@@ -3082,43 +3238,45 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** Additional information is available at [limits | Limits in SQLite].
 **
 ** <dl>
-** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
+** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt>
 ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
+** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
 ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_COLUMN</dt>
+** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt>
 ** <dd>The maximum number of columns in a table definition or in the
 ** result set of a [SELECT] or the maximum number of columns in an index
 ** or in an ORDER BY or GROUP BY clause.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
+** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
 ** <dd>The maximum depth of the parse tree on any expression.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
+** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
 ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
+** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
 ** <dd>The maximum number of instructions in a virtual machine program
 ** used to implement an SQL statement.  This limit is not currently
 ** enforced, though that might be added in some future release of
 ** SQLite.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
+** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
 ** <dd>The maximum number of arguments on a function.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
+** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
 ** <dd>The maximum number of [ATTACH | attached databases].)^</dd>
 **
+** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]]
 ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt>
 ** <dd>The maximum length of the pattern argument to the [LIKE] or
 ** [GLOB] operators.</dd>)^
 **
+** [[SQLITE_LIMIT_VARIABLE_NUMBER]]
 ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
 ** <dd>The maximum index number of any [parameter] in an SQL statement.)^
 **
-** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
+** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
 ** <dd>The maximum depth of recursion for triggers.</dd>)^
 ** </dl>
 */
@@ -3647,7 +3805,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
 ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
 ** database locks it needs to do its job.  ^If the statement is a [COMMIT]
 ** or occurs outside of an explicit transaction, then you can retry the
-** statement.  If the statement is not a [COMMIT] and occurs within a
+** statement.  If the statement is not a [COMMIT] and occurs within an
 ** explicit transaction then you should rollback the transaction before
 ** continuing.
 **
@@ -3926,7 +4084,7 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
 ** CAPI3REF: Destroy A Prepared Statement Object
 **
 ** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the most recent evaluation of the statement encountered no errors or
+** ^If the most recent evaluation of the statement encountered no errors
 ** or if the statement is never been evaluated, then sqlite3_finalize() returns
 ** SQLITE_OK.  ^If the most recent evaluation of statement S failed, then
 ** sqlite3_finalize(S) returns the appropriate [error code] or
@@ -5153,6 +5311,11 @@ struct sqlite3_module {
                        void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
                        void **ppArg);
   int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
+  /* The methods above are in version 1 of the sqlite_module object. Those 
+  ** below are for version 2 and greater. */
+  int (*xSavepoint)(sqlite3_vtab *pVTab, int);
+  int (*xRelease)(sqlite3_vtab *pVTab, int);
+  int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
 };
 
 /*
@@ -5835,7 +5998,7 @@ struct sqlite3_mutex_methods {
 **
 ** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
 ** the routine should return 1.   This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist.  But the
+** clearly the mutex cannot be held if it does not exist.  But
 ** the reason the mutex does not exist is because the build is not
 ** using mutexes.  And we do not want the assert() containing the
 ** call to sqlite3_mutex_held() to fail, so a non-zero return is
@@ -5958,7 +6121,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_ISKEYWORD               16
 #define SQLITE_TESTCTRL_PGHDRSZ                 17
 #define SQLITE_TESTCTRL_SCRATCHMALLOC           18
-#define SQLITE_TESTCTRL_LAST                    18
+#define SQLITE_TESTCTRL_LOCALTIME_FAULT         19
+#define SQLITE_TESTCTRL_LAST                    19
 
 /*
 ** CAPI3REF: SQLite Runtime Status
@@ -5967,7 +6131,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 ** about the performance of SQLite, and optionally to reset various
 ** highwater marks.  ^The first argument is an integer code for
 ** the specific parameter to measure.  ^(Recognized integer codes
-** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
+** are of the form [status parameters | SQLITE_STATUS_...].)^
 ** ^The current value of the parameter is returned into *pCurrent.
 ** ^The highest recorded value is returned in *pHighwater.  ^If the
 ** resetFlag is true, then the highest record value is reset after
@@ -5994,12 +6158,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 
 /*
 ** CAPI3REF: Status Parameters
+** KEYWORDS: {status parameters}
 **
 ** These integer constants designate various run-time status parameters
 ** that can be returned by [sqlite3_status()].
 **
 ** <dl>
-** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
+** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
 ** <dd>This parameter is the current amount of memory checked out
 ** using [sqlite3_malloc()], either directly or indirectly.  The
 ** figure includes calls made to [sqlite3_malloc()] by the application
@@ -6009,23 +6174,24 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** this parameter.  The amount returned is the sum of the allocation
 ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
+** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
 ** internal equivalents).  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
+** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
 ** <dd>This parameter records the number of separate memory allocations
 ** currently checked out.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
+** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
 ** <dd>This parameter returns the number of pages used out of the
 ** [pagecache memory allocator] that was configured using 
 ** [SQLITE_CONFIG_PAGECACHE].  The
 ** value returned is in pages, not in bytes.</dd>)^
 **
+** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] 
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of page cache
 ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
@@ -6035,13 +6201,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
 ** no space was left in the page cache.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
+** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [pagecache memory allocator].  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
 ** <dd>This parameter returns the number of allocations used out of the
 ** [scratch memory allocator] configured using
 ** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
@@ -6049,7 +6215,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** outstanding at time, this parameter also reports the number of threads
 ** using scratch memory at the same time.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
+** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of scratch memory
 ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The values
@@ -6059,13 +6225,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** slots were available.
 ** </dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [scratch memory allocator].  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
+** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
 ** <dd>This parameter records the deepest parser stack.  It is only
 ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
 ** </dl>
@@ -6090,9 +6256,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** about a single [database connection].  ^The first argument is the
 ** database connection object to be interrogated.  ^The second argument
 ** is an integer constant, taken from the set of
-** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
+** [SQLITE_DBSTATUS options], that
 ** determines the parameter to interrogate.  The set of 
-** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
+** [SQLITE_DBSTATUS options] is likely
 ** to grow in future releases of SQLite.
 **
 ** ^The current value of the requested parameter is written into *pCur
@@ -6109,6 +6275,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 
 /*
 ** CAPI3REF: Status Parameters for database connections
+** KEYWORDS: {SQLITE_DBSTATUS options}
 **
 ** These constants are the available integer "verbs" that can be passed as
 ** the second argument to the [sqlite3_db_status()] interface.
@@ -6120,15 +6287,16 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** if a discontinued or unsupported verb is invoked.
 **
 ** <dl>
-** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
 ** <dd>This parameter returns the number of lookaside memory slots currently
 ** checked out.</dd>)^
 **
-** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
 ** <dd>This parameter returns the number malloc attempts that were 
 ** satisfied using lookaside memory. Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
 ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
 ** <dd>This parameter returns the number malloc attempts that might have
 ** been satisfied using lookaside memory but failed due to the amount of
@@ -6136,6 +6304,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
 ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
 ** <dd>This parameter returns the number malloc attempts that might have
 ** been satisfied using lookaside memory but failed due to all lookaside
@@ -6143,12 +6312,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
-** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
+** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used by all pager caches associated with the database connection.)^
 ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
 **
-** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
+** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used to store the schema for all databases associated
 ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ 
@@ -6157,7 +6326,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** [shared cache mode] being enabled.
 ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
 **
-** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
+** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** and lookaside memory used by all prepared statements associated with
 ** the database connection.)^
@@ -6179,7 +6348,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** CAPI3REF: Prepared Statement Status
 **
 ** ^(Each prepared statement maintains various
-** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
+** [SQLITE_STMTSTATUS counters] that measure the number
 ** of times it has performed specific operations.)^  These counters can
 ** be used to monitor the performance characteristics of the prepared
 ** statements.  For example, if the number of table steps greatly exceeds
@@ -6190,7 +6359,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** ^(This interface is used to retrieve and reset counter values from
 ** a [prepared statement].  The first argument is the prepared statement
 ** object to be interrogated.  The second argument
-** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter]
+** is an integer code for a specific [SQLITE_STMTSTATUS counter]
 ** to be interrogated.)^
 ** ^The current value of the requested counter is returned.
 ** ^If the resetFlg is true, then the counter is reset to zero after this
@@ -6202,24 +6371,25 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
 
 /*
 ** CAPI3REF: Status Parameters for prepared statements
+** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters}
 **
 ** These preprocessor macros define integer codes that name counter
 ** values associated with the [sqlite3_stmt_status()] interface.
 ** The meanings of the various counters are as follows:
 **
 ** <dl>
-** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
 ** <dd>^This is the number of times that SQLite has stepped forward in
 ** a table as part of a full table scan.  Large numbers for this counter
 ** may indicate opportunities for performance improvement through 
 ** careful use of indices.</dd>
 **
-** <dt>SQLITE_STMTSTATUS_SORT</dt>
+** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
 ** <dd>^This is the number of sort operations that have occurred.
 ** A non-zero value in this counter may indicate an opportunity to
 ** improvement performance through careful use of indices.</dd>
 **
-** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
+** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
 ** <dd>^This is the number of rows inserted into transient indices that
 ** were created automatically in order to help joins run faster.
 ** A non-zero value in this counter may indicate an opportunity to
@@ -6270,6 +6440,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** the application may discard the parameter after the call to
 ** [sqlite3_config()] returns.)^
 **
+** [[the xInit() page cache method]]
 ** ^(The xInit() method is called once for each effective 
 ** call to [sqlite3_initialize()])^
 ** (usually only once during the lifetime of the process). ^(The xInit()
@@ -6280,6 +6451,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** built-in default page cache is used instead of the application defined
 ** page cache.)^
 **
+** [[the xShutdown() page cache method]]
 ** ^The xShutdown() method is called by [sqlite3_shutdown()].
 ** It can be used to clean up 
 ** any outstanding resources before process shutdown, if required.
@@ -6294,6 +6466,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^SQLite will never invoke xInit() more than once without an intervening
 ** call to xShutdown().
 **
+** [[the xCreate() page cache methods]]
 ** ^SQLite invokes the xCreate() method to construct a new cache instance.
 ** SQLite will typically create one cache instance for each open database file,
 ** though this is not guaranteed. ^The
@@ -6318,6 +6491,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^Hence, a cache created with bPurgeable false will
 ** never contain any unpinned pages.
 **
+** [[the xCachesize() page cache method]]
 ** ^(The xCachesize() method may be called at any time by SQLite to set the
 ** suggested maximum cache-size (number of pages stored by) the cache
 ** instance passed as the first argument. This is the value configured using
@@ -6325,14 +6499,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** parameter, the implementation is not required to do anything with this
 ** value; it is advisory only.
 **
+** [[the xPagecount() page cache methods]]
 ** The xPagecount() method must return the number of pages currently
 ** stored in the cache, both pinned and unpinned.
 ** 
+** [[the xFetch() page cache methods]]
 ** The xFetch() method locates a page in the cache and returns a pointer to 
 ** the page, or a NULL pointer.
 ** A "page", in this context, means a buffer of szPage bytes aligned at an
 ** 8-byte boundary. The page to be fetched is determined by the key. ^The
-** mimimum key value is 1.  After it has been retrieved using xFetch, the page 
+** minimum key value is 1.  After it has been retrieved using xFetch, the page 
 ** is considered to be "pinned".
 **
 ** If the requested page is already in the page cache, then the page cache
@@ -6356,6 +6532,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** attempt to unpin one or more cache pages by spilling the content of
 ** pinned pages to disk and synching the operating system disk cache.
 **
+** [[the xUnpin() page cache method]]
 ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
 ** as its second argument.  If the third parameter, discard, is non-zero,
 ** then the page must be evicted from the cache.
@@ -6368,6 +6545,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** call to xUnpin() unpins the page regardless of the number of prior calls 
 ** to xFetch().
 **
+** [[the xRekey() page cache methods]]
 ** The xRekey() method is used to change the key value associated with the
 ** page passed as the second argument. If the cache
 ** previously contains an entry associated with newKey, it must be
@@ -6380,6 +6558,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** of these pages are pinned, they are implicitly unpinned, meaning that
 ** they can be safely discarded.
 **
+** [[the xDestroy() page cache method]]
 ** ^The xDestroy() method is used to delete a cache allocated by xCreate().
 ** All resources associated with the specified cache should be freed. ^After
 ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
@@ -6442,7 +6621,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** There should be exactly one call to sqlite3_backup_finish() for each
 ** successful call to sqlite3_backup_init().
 **
-** <b>sqlite3_backup_init()</b>
+** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b>
 **
 ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the 
 ** [database connection] associated with the destination database 
@@ -6469,7 +6648,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** sqlite3_backup_finish() functions to perform the specified backup 
 ** operation.
 **
-** <b>sqlite3_backup_step()</b>
+** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
 **
 ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between 
 ** the source and destination databases specified by [sqlite3_backup] object B.
@@ -6526,7 +6705,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** by the backup operation, then the backup database is automatically
 ** updated at the same time.
 **
-** <b>sqlite3_backup_finish()</b>
+** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
 **
 ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the 
 ** application wishes to abandon the backup operation, the application
@@ -6549,7 +6728,8 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** is not a permanent error and does not affect the return value of
 ** sqlite3_backup_finish().
 **
-** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b>
+** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
 **
 ** ^Each call to sqlite3_backup_step() sets two values inside
 ** the [sqlite3_backup] object: the number of pages still to be backed
@@ -6935,6 +7115,93 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
 #define SQLITE_CHECKPOINT_FULL    1
 #define SQLITE_CHECKPOINT_RESTART 2
 
+/*
+** CAPI3REF: Virtual Table Interface Configuration
+**
+** This function may be called by either the [xConnect] or [xCreate] method
+** of a [virtual table] implementation to configure
+** various facets of the virtual table interface.
+**
+** If this interface is invoked outside the context of an xConnect or
+** xCreate virtual table method then the behavior is undefined.
+**
+** At present, there is only one option that may be configured using
+** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
+** may be added in the future.
+*/
+SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+
+/*
+** CAPI3REF: Virtual Table Configuration Options
+**
+** These macros define the various options to the
+** [sqlite3_vtab_config()] interface that [virtual table] implementations
+** can use to customize and optimize their behavior.
+**
+** <dl>
+** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
+** where X is an integer.  If X is zero, then the [virtual table] whose
+** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
+** support constraints.  In this configuration (which is the default) if
+** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
+** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
+** specified as part of the users SQL statement, regardless of the actual
+** ON CONFLICT mode specified.
+**
+** If X is non-zero, then the virtual table implementation guarantees
+** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
+** any modifications to internal or persistent data structures have been made.
+** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite 
+** is able to roll back a statement or database transaction, and abandon
+** or continue processing the current SQL statement as appropriate. 
+** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
+** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
+** had been ABORT.
+**
+** Virtual table implementations that are required to handle OR REPLACE
+** must do so within the [xUpdate] method. If a call to the 
+** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
+** CONFLICT policy is REPLACE, the virtual table implementation should 
+** silently replace the appropriate rows within the xUpdate callback and
+** return SQLITE_OK. Or, if this is not possible, it may return
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
+** constraint handling.
+** </dl>
+*/
+#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+
+/*
+** CAPI3REF: Determine The Virtual Table Conflict Policy
+**
+** This function may only be called from within a call to the [xUpdate] method
+** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
+** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
+** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
+** of the SQL statement that triggered the call to the [xUpdate] method of the
+** [virtual table].
+*/
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+
+/*
+** CAPI3REF: Conflict resolution modes
+**
+** These constants are returned by [sqlite3_vtab_on_conflict()] to
+** inform a [virtual table] implementation what the [ON CONFLICT] mode
+** is for the SQL statement being evaluated.
+**
+** Note that the [SQLITE_IGNORE] constant is also used as a potential
+** return value from the [sqlite3_set_authorizer()] callback and that
+** [SQLITE_ABORT] is also a [result code].
+*/
+#define SQLITE_ROLLBACK 1
+/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */
+#define SQLITE_FAIL     3
+/* #define SQLITE_ABORT 4  // Also an error code */
+#define SQLITE_REPLACE  5
+
+
 
 /*
 ** Undo the hack that converts floating point types to integer for
@@ -7601,6 +7868,7 @@ typedef struct TriggerPrg TriggerPrg;
 typedef struct TriggerStep TriggerStep;
 typedef struct UnpackedRecord UnpackedRecord;
 typedef struct VTable VTable;
+typedef struct VtabCtx VtabCtx;
 typedef struct Walker Walker;
 typedef struct WherePlan WherePlan;
 typedef struct WhereInfo WhereInfo;
@@ -7657,6 +7925,7 @@ typedef struct BtShared BtShared;
 
 
 SQLITE_PRIVATE int sqlite3BtreeOpen(
+  sqlite3_vfs *pVfs,       /* VFS to use with this b-tree */
   const char *zFilename,   /* Name of database file to open */
   sqlite3 *db,             /* Associated database connection */
   Btree **ppBtree,         /* Return open Btree* here */
@@ -8217,6 +8486,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
 SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
 SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
@@ -8230,7 +8500,7 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
+SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
 SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);
 SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*);
@@ -8239,6 +8509,7 @@ SQLITE_PRIVATE   int sqlite3VdbeAssertMayAbort(Vdbe *, int);
 SQLITE_PRIVATE   void sqlite3VdbeTrace(Vdbe*,FILE*);
 #endif
 SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*);
 SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int);
 SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
@@ -9015,7 +9286,7 @@ struct Db {
 ** A thread must be holding a mutex on the corresponding Btree in order
 ** to access Schema content.  This implies that the thread must also be
 ** holding a mutex on the sqlite3 connection pointer that owns the Btree.
-** For a TEMP Schema, on the connection mutex is required.
+** For a TEMP Schema, only the connection mutex is required.
 */
 struct Schema {
   int schema_cookie;   /* Database schema version number for this file */
@@ -9136,7 +9407,7 @@ struct sqlite3 {
   int nDb;                      /* Number of backends currently in use */
   Db *aDb;                      /* All backends */
   int flags;                    /* Miscellaneous flags. See below */
-  int openFlags;                /* Flags passed to sqlite3_vfs.xOpen() */
+  unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
   int errCode;                  /* Most recent error code (SQLITE_*) */
   int errMask;                  /* & result codes with this before returning */
   u8 autoCommit;                /* The auto-commit flag. */
@@ -9145,6 +9416,7 @@ struct sqlite3 {
   u8 dfltLockMode;              /* Default locking-mode for attached dbs */
   signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
   u8 suppressErr;               /* Do not issue error messages if true */
+  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
   int nextPagesize;             /* Pagesize after VACUUM if >0 */
   int nTable;                   /* Number of tables in the database */
   CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
@@ -9203,7 +9475,7 @@ struct sqlite3 {
 #endif
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   Hash aModule;                 /* populated by sqlite3_create_module() */
-  Table *pVTab;                 /* vtab with active Connect/Create method */
+  VtabCtx *pVtabCtx;            /* Context for active vtab connect/create */
   VTable **aVTrans;             /* Virtual tables with open transactions */
   int nVTrans;                  /* Allocated size of aVTrans */
   VTable *pDisconnect;    /* Disconnect these in next sqlite3_prepare() */
@@ -9287,6 +9559,7 @@ struct sqlite3 {
 #define SQLITE_IndexCover     0x10        /* Disable index covering table */
 #define SQLITE_GroupByOrder   0x20        /* Disable GROUPBY cover of ORDERBY */
 #define SQLITE_FactorOutConst 0x40        /* Disable factoring out constants */
+#define SQLITE_IdxRealAsInt   0x80        /* Store REAL as INT in indices */
 #define SQLITE_OptMask        0xff        /* Mask of all disablable opts */
 
 /*
@@ -9566,6 +9839,8 @@ struct VTable {
   Module *pMod;             /* Pointer to module implementation */
   sqlite3_vtab *pVtab;      /* Pointer to vtab instance */
   int nRef;                 /* Number of pointers to this structure */
+  u8 bConstraint;           /* True if constraints are supported */
+  int iSavepoint;           /* Depth of the SAVEPOINT stack */
   VTable *pNext;            /* Next in linked list (see above) */
 };
 
@@ -10560,9 +10835,8 @@ struct Parse {
   ** each recursion */
 
   int nVar;            /* Number of '?' variables seen in the SQL so far */
-  int nVarExpr;        /* Number of used slots in apVarExpr[] */
-  int nVarExprAlloc;   /* Number of allocated slots in apVarExpr[] */
-  Expr **apVarExpr;    /* Pointers to :aaa and $aaaa wildcard expressions */
+  int nzVar;           /* Number of available slots in azVar[] */
+  char **azVar;        /* Pointers to names of parameters */
   Vdbe *pReprepare;    /* VM being reprepared (sqlite3Reprepare()) */
   int nAlias;          /* Number of aliased result set columns */
   int nAliasAlloc;     /* Number of allocated slots for aAlias[] */
@@ -10754,6 +11028,7 @@ struct Sqlite3Config {
   int bMemstat;                     /* True to enable memory status */
   int bCoreMutex;                   /* True to enable core mutexing */
   int bFullMutex;                   /* True to enable full mutexing */
+  int bOpenUri;                     /* True to interpret filenames as URIs */
   int mxStrlen;                     /* Maximum string length */
   int szLookaside;                  /* Default lookaside buffer size */
   int nLookaside;                   /* Default lookaside buffer count */
@@ -10782,6 +11057,7 @@ struct Sqlite3Config {
   int nRefInitMutex;                /* Number of users of pInitMutex */
   void (*xLog)(void*,int,const char*); /* Function for logging */
   void *pLogArg;                       /* First argument to xLog() */
+  int bLocaltimeFault;              /* True to fail localtime() calls */
 };
 
 /*
@@ -11003,6 +11279,8 @@ SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
 SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
 SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
 SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*);
+SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
+                    sqlite3_vfs**,char**,char **);
 
 SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32);
 SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32);
@@ -11207,7 +11485,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
 SQLITE_PRIVATE int sqlite3Atoi(const char*);
 SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
 SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
-SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**);
+SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8*, const u8**);
 
 /*
 ** Routines to read and write variable-length integers.  These used to
@@ -11253,6 +11531,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
 SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
 SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
+SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
@@ -11268,6 +11547,12 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
 SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
 SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
 SQLITE_PRIVATE int sqlite3AbsInt32(int);
+#ifdef SQLITE_ENABLE_8_3_NAMES
+SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
+#else
+# define sqlite3FileSuffix3(X,Y)
+#endif
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z);
 
 SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
 SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
@@ -11377,6 +11662,7 @@ SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
 #  define sqlite3VtabLock(X) 
 #  define sqlite3VtabUnlock(X)
 #  define sqlite3VtabUnlockList(X)
+#  define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
 #else
 SQLITE_PRIVATE    void sqlite3VtabClear(sqlite3 *db, Table*);
 SQLITE_PRIVATE    int sqlite3VtabSync(sqlite3 *db, char **);
@@ -11385,6 +11671,7 @@ SQLITE_PRIVATE    int sqlite3VtabCommit(sqlite3 *db);
 SQLITE_PRIVATE    void sqlite3VtabLock(VTable *);
 SQLITE_PRIVATE    void sqlite3VtabUnlock(VTable *);
 SQLITE_PRIVATE    void sqlite3VtabUnlockList(sqlite3*);
+SQLITE_PRIVATE    int sqlite3VtabSavepoint(sqlite3 *, int, int);
 #  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
 #endif
 SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
@@ -11691,7 +11978,9 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
 };
 #endif
 
-
+#ifndef SQLITE_USE_URI
+# define  SQLITE_USE_URI 0
+#endif
 
 /*
 ** The following singleton contains the global configuration for
@@ -11701,6 +11990,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    SQLITE_DEFAULT_MEMSTATUS,  /* bMemstat */
    1,                         /* bCoreMutex */
    SQLITE_THREADSAFE==1,      /* bFullMutex */
+   SQLITE_USE_URI,            /* bOpenUri */
    0x7ffffffe,                /* mxStrlen */
    100,                       /* szLookaside */
    500,                       /* nLookaside */
@@ -11728,6 +12018,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    0,                         /* nRefInitMutex */
    0,                         /* xLog */
    0,                         /* pLogArg */
+   0,                         /* bLocaltimeFault */
 };
 
 
@@ -12480,11 +12771,11 @@ struct Vdbe {
   Mem *aVar;              /* Values for the OP_Variable opcode. */
   char **azVar;           /* Name of variables */
   ynVar nVar;             /* Number of entries in aVar[] */
+  ynVar nzVar;            /* Number of entries in azVar[] */
   u32 cacheCtr;           /* VdbeCursor row cache generation counter */
   int pc;                 /* The program counter */
   int rc;                 /* Value to return */
   u8 errorAction;         /* Recovery action to do in case of an error */
-  u8 okVar;               /* True if azVar[] has been initialized */
   u8 explain;             /* True if EXPLAIN present on SQL command */
   u8 changeCntOn;         /* True to update the change-counter */
   u8 expired;             /* True if the VM needs to be recompiled */
@@ -12878,22 +13169,6 @@ SQLITE_API int sqlite3_db_status(
 
 #ifndef SQLITE_OMIT_DATETIME_FUNCS
 
-/*
-** On recent Windows platforms, the localtime_s() function is available
-** as part of the "Secure CRT". It is essentially equivalent to 
-** localtime_r() available under most POSIX platforms, except that the 
-** order of the parameters is reversed.
-**
-** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
-**
-** If the user has not indicated to use localtime_r() or localtime_s()
-** already, check for an MSVC build environment that provides 
-** localtime_s().
-*/
-#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
-     defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
-#define HAVE_LOCALTIME_S 1
-#endif
 
 /*
 ** A structure for holding a single date and time.
@@ -13239,15 +13514,83 @@ static void clearYMD_HMS_TZ(DateTime *p){
   p->validTZ = 0;
 }
 
+/*
+** On recent Windows platforms, the localtime_s() function is available
+** as part of the "Secure CRT". It is essentially equivalent to 
+** localtime_r() available under most POSIX platforms, except that the 
+** order of the parameters is reversed.
+**
+** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
+**
+** If the user has not indicated to use localtime_r() or localtime_s()
+** already, check for an MSVC build environment that provides 
+** localtime_s().
+*/
+#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
+     defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)
+#define HAVE_LOCALTIME_S 1
+#endif
+
+#ifndef SQLITE_OMIT_LOCALTIME
+/*
+** The following routine implements the rough equivalent of localtime_r()
+** using whatever operating-system specific localtime facility that
+** is available.  This routine returns 0 on success and
+** non-zero on any kind of error.
+**
+** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
+** routine will always fail.
+*/
+static int osLocaltime(time_t *t, struct tm *pTm){
+  int rc;
+#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
+      && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
+  struct tm *pX;
+  sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+  sqlite3_mutex_enter(mutex);
+  pX = localtime(t);
+#ifndef SQLITE_OMIT_BUILTIN_TEST
+  if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
+#endif
+  if( pX ) *pTm = *pX;
+  sqlite3_mutex_leave(mutex);
+  rc = pX==0;
+#else
+#ifndef SQLITE_OMIT_BUILTIN_TEST
+  if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
+#endif
+#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
+  rc = localtime_r(t, pTm)==0;
+#else
+  rc = localtime_s(pTm, t);
+#endif /* HAVE_LOCALTIME_R */
+#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
+  return rc;
+}
+#endif /* SQLITE_OMIT_LOCALTIME */
+
+
 #ifndef SQLITE_OMIT_LOCALTIME
 /*
-** Compute the difference (in milliseconds)
-** between localtime and UTC (a.k.a. GMT)
-** for the time value p where p is in UTC.
+** Compute the difference (in milliseconds) between localtime and UTC
+** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
+** return this value and set *pRc to SQLITE_OK. 
+**
+** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
+** is undefined in this case.
 */
-static sqlite3_int64 localtimeOffset(DateTime *p){
+static sqlite3_int64 localtimeOffset(
+  DateTime *p,                    /* Date at which to calculate offset */
+  sqlite3_context *pCtx,          /* Write error here if one occurs */
+  int *pRc                        /* OUT: Error code. SQLITE_OK or ERROR */
+){
   DateTime x, y;
   time_t t;
+  struct tm sLocal;
+
+  /* Initialize the contents of sLocal to avoid a compiler warning. */
+  memset(&sLocal, 0, sizeof(sLocal));
+
   x = *p;
   computeYMD_HMS(&x);
   if( x.Y<1971 || x.Y>=2038 ){
@@ -13265,47 +13608,23 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
   x.validJD = 0;
   computeJD(&x);
   t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
-#ifdef HAVE_LOCALTIME_R
-  {
-    struct tm sLocal;
-    localtime_r(&t, &sLocal);
-    y.Y = sLocal.tm_year + 1900;
-    y.M = sLocal.tm_mon + 1;
-    y.D = sLocal.tm_mday;
-    y.h = sLocal.tm_hour;
-    y.m = sLocal.tm_min;
-    y.s = sLocal.tm_sec;
-  }
-#elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S
-  {
-    struct tm sLocal;
-    localtime_s(&sLocal, &t);
-    y.Y = sLocal.tm_year + 1900;
-    y.M = sLocal.tm_mon + 1;
-    y.D = sLocal.tm_mday;
-    y.h = sLocal.tm_hour;
-    y.m = sLocal.tm_min;
-    y.s = sLocal.tm_sec;
-  }
-#else
-  {
-    struct tm *pTm;
-    sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
-    pTm = localtime(&t);
-    y.Y = pTm->tm_year + 1900;
-    y.M = pTm->tm_mon + 1;
-    y.D = pTm->tm_mday;
-    y.h = pTm->tm_hour;
-    y.m = pTm->tm_min;
-    y.s = pTm->tm_sec;
-    sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+  if( osLocaltime(&t, &sLocal) ){
+    sqlite3_result_error(pCtx, "local time unavailable", -1);
+    *pRc = SQLITE_ERROR;
+    return 0;
   }
-#endif
+  y.Y = sLocal.tm_year + 1900;
+  y.M = sLocal.tm_mon + 1;
+  y.D = sLocal.tm_mday;
+  y.h = sLocal.tm_hour;
+  y.m = sLocal.tm_min;
+  y.s = sLocal.tm_sec;
   y.validYMD = 1;
   y.validHMS = 1;
   y.validJD = 0;
   y.validTZ = 0;
   computeJD(&y);
+  *pRc = SQLITE_OK;
   return y.iJD - x.iJD;
 }
 #endif /* SQLITE_OMIT_LOCALTIME */
@@ -13329,9 +13648,12 @@ static sqlite3_int64 localtimeOffset(DateTime *p){
 **     localtime
 **     utc
 **
-** Return 0 on success and 1 if there is any kind of error.
+** Return 0 on success and 1 if there is any kind of error. If the error
+** is in a system call (i.e. localtime()), then an error message is written
+** to context pCtx. If the error is an unrecognized modifier, no error is
+** written to pCtx.
 */
-static int parseModifier(const char *zMod, DateTime *p){
+static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
   int rc = 1;
   int n;
   double r;
@@ -13351,9 +13673,8 @@ static int parseModifier(const char *zMod, DateTime *p){
       */
       if( strcmp(z, "localtime")==0 ){
         computeJD(p);
-        p->iJD += localtimeOffset(p);
+        p->iJD += localtimeOffset(p, pCtx, &rc);
         clearYMD_HMS_TZ(p);
-        rc = 0;
       }
       break;
     }
@@ -13374,11 +13695,12 @@ static int parseModifier(const char *zMod, DateTime *p){
       else if( strcmp(z, "utc")==0 ){
         sqlite3_int64 c1;
         computeJD(p);
-        c1 = localtimeOffset(p);
-        p->iJD -= c1;
-        clearYMD_HMS_TZ(p);
-        p->iJD += c1 - localtimeOffset(p);
-        rc = 0;
+        c1 = localtimeOffset(p, pCtx, &rc);
+        if( rc==SQLITE_OK ){
+          p->iJD -= c1;
+          clearYMD_HMS_TZ(p);
+          p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
+        }
       }
 #endif
       break;
@@ -13559,9 +13881,8 @@ static int isDate(
     }
   }
   for(i=1; i<argc; i++){
-    if( (z = sqlite3_value_text(argv[i]))==0 || parseModifier((char*)z, p) ){
-      return 1;
-    }
+    z = sqlite3_value_text(argv[i]);
+    if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
   }
   return 0;
 }
@@ -17950,7 +18271,7 @@ static int mallocWithAlarm(int n, void **pp){
   sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
   if( mem0.alarmCallback!=0 ){
     int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
-    if( nUsed+nFull >= mem0.alarmThreshold ){
+    if( nUsed >= mem0.alarmThreshold - nFull ){
       mem0.nearlyFull = 1;
       sqlite3MallocAlarm(nFull);
     }else{
@@ -18191,7 +18512,7 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
 ** Change the size of an existing memory allocation
 */
 SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
-  int nOld, nNew;
+  int nOld, nNew, nDiff;
   void *pNew;
   if( pOld==0 ){
     return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */
@@ -18214,9 +18535,10 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){
   }else if( sqlite3GlobalConfig.bMemstat ){
     sqlite3_mutex_enter(mem0.mutex);
     sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes);
-    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= 
-          mem0.alarmThreshold ){
-      sqlite3MallocAlarm(nNew-nOld);
+    nDiff = nNew - nOld;
+    if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= 
+          mem0.alarmThreshold-nDiff ){
+      sqlite3MallocAlarm(nDiff);
     }
     assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
     assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
@@ -19801,7 +20123,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
         || (c&0xFFFFF800)==0xD800                          \
         || (c&0xFFFFFFFE)==0xFFFE ){  c = 0xFFFD; }        \
   }
-SQLITE_PRIVATE int sqlite3Utf8Read(
+SQLITE_PRIVATE u32 sqlite3Utf8Read(
   const unsigned char *zIn,       /* First byte of UTF-8 character */
   const unsigned char **pzNext    /* Write first byte past UTF-8 char here */
 ){
@@ -21182,13 +21504,12 @@ SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
 
 
 
-#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
 /*
 ** Translate a single byte of Hex into an integer.
 ** This routine only works if h really is a valid hexadecimal
 ** character:  0..9a..fA..F
 */
-static u8 hexToInt(int h){
+SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
   assert( (h>='0' && h<='9') ||  (h>='a' && h<='f') ||  (h>='A' && h<='F') );
 #ifdef SQLITE_ASCII
   h += 9*(1&(h>>6));
@@ -21198,7 +21519,6 @@ static u8 hexToInt(int h){
 #endif
   return (u8)(h & 0xf);
 }
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
 
 #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
 /*
@@ -21215,7 +21535,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
   n--;
   if( zBlob ){
     for(i=0; i<n; i+=2){
-      zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]);
+      zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]);
     }
     zBlob[i/2] = 0;
   }
@@ -21348,6 +21668,32 @@ SQLITE_PRIVATE int sqlite3AbsInt32(int x){
   return -x;
 }
 
+#ifdef SQLITE_ENABLE_8_3_NAMES
+/*
+** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database
+** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and
+** if filename in z[] has a suffix (a.k.a. "extension") that is longer than
+** three characters, then shorten the suffix on z[] to be the last three
+** characters of the original suffix.
+**
+** Examples:
+**
+**     test.db-journal    =>   test.nal
+**     test.db-wal        =>   test.wal
+**     test.db-shm        =>   test.shm
+*/
+SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
+  const char *zOk;
+  zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names");
+  if( zOk && sqlite3GetBoolean(zOk) ){
+    int i, sz;
+    sz = sqlite3Strlen30(z);
+    for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
+    if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4);
+  }
+}
+#endif
+
 /************** End of util.c ************************************************/
 /************** Begin file hash.c ********************************************/
 /*
@@ -24054,6 +24400,10 @@ SQLITE_API int sqlite3_os_end(void){
 # include <sys/mount.h>
 #endif
 
+#ifdef HAVE_UTIME
+# include <utime.h>
+#endif
+
 /*
 ** Allowed values of unixFile.fsFlags
 */
@@ -24401,6 +24751,18 @@ SQLITE_API int sqlite3_open_file_count = 0;
 #define threadid 0
 #endif
 
+/*
+** Different Unix systems declare open() in different ways.  Same use
+** open(const char*,int,mode_t).  Others use open(const char*,int,...).
+** The difference is important when using a pointer to the function.
+**
+** The safest way to deal with the problem is to always use this wrapper
+** which always has the same well-defined interface.
+*/
+static int posixOpen(const char *zFile, int flags, int mode){
+  return open(zFile, flags, mode);
+}
+
 /*
 ** Many system calls are accessed through pointer-to-functions so that
 ** they may be overridden at runtime to facilitate fault injection during
@@ -24412,8 +24774,8 @@ static struct unix_syscall {
   sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
   sqlite3_syscall_ptr pDefault; /* Default value */
 } aSyscall[] = {
-  { "open",         (sqlite3_syscall_ptr)open,       0  },
-#define osOpen      ((int(*)(const char*,int,...))aSyscall[0].pCurrent)
+  { "open",         (sqlite3_syscall_ptr)posixOpen,  0  },
+#define osOpen      ((int(*)(const char*,int,int))aSyscall[0].pCurrent)
 
   { "close",        (sqlite3_syscall_ptr)close,      0  },
 #define osClose     ((int(*)(int))aSyscall[1].pCurrent)
@@ -24450,7 +24812,7 @@ static struct unix_syscall {
   { "read",         (sqlite3_syscall_ptr)read,       0  },
 #define osRead      ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent)
 
-#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
   { "pread",        (sqlite3_syscall_ptr)pread,      0  },
 #else
   { "pread",        (sqlite3_syscall_ptr)0,          0  },
@@ -24467,7 +24829,7 @@ static struct unix_syscall {
   { "write",        (sqlite3_syscall_ptr)write,      0  },
 #define osWrite     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
 
-#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE)
+#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE
   { "pwrite",       (sqlite3_syscall_ptr)pwrite,     0  },
 #else
   { "pwrite",       (sqlite3_syscall_ptr)0,          0  },
@@ -25053,7 +25415,7 @@ struct unixInodeInfo {
   UnixUnusedFd *pUnused;          /* Unused file descriptors to close */
   unixInodeInfo *pNext;           /* List of all unixInodeInfo objects */
   unixInodeInfo *pPrev;           /*    .... doubly linked */
-#if defined(SQLITE_ENABLE_LOCKING_STYLE)
+#if SQLITE_ENABLE_LOCKING_STYLE
   unsigned long long sharedByte;  /* for AFP simulated shared lock */
 #endif
 #if OS_VXWORKS
@@ -26047,8 +26409,10 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
   */
   if( pFile->eFileLock > NO_LOCK ){
     pFile->eFileLock = eFileLock;
-#if !OS_VXWORKS
     /* Always update the timestamp on the old file */
+#ifdef HAVE_UTIME
+    utime(zLockFile, NULL);
+#else
     utimes(zLockFile, NULL);
 #endif
     return SQLITE_OK;
@@ -27210,7 +27574,7 @@ static int unixWrite(
   SimulateDiskfullError(( wrote=0, amt=1 ));
 
   if( amt>0 ){
-    if( wrote<0 ){
+    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
       /* lastErrno set by seekAndWrite */
       return SQLITE_IOERR_WRITE;
     }else{
@@ -27645,7 +28009,8 @@ struct unixShmNode {
   char *zFilename;           /* Name of the mmapped file */
   int h;                     /* Open file descriptor */
   int szRegion;              /* Size of shared-memory regions */
-  int nRegion;               /* Size of array apRegion */
+  u16 nRegion;               /* Size of array apRegion */
+  u8 isReadonly;             /* True if read-only */
   char **apRegion;           /* Array of mapped shared-memory regions */
   int nRef;                  /* Number of unixShm objects pointing to this */
   unixShm *pFirst;           /* All unixShm objects pointing to this */
@@ -27877,6 +28242,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
                      (u32)sStat.st_ino, (u32)sStat.st_dev);
 #else
     sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath);
+    sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
 #endif
     pShmNode->h = -1;
     pDbFd->pInode->pShmNode = pShmNode;
@@ -27891,8 +28257,17 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
       pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
                                (sStat.st_mode & 0777));
       if( pShmNode->h<0 ){
-        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
-        goto shm_open_err;
+        const char *zRO;
+        zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
+        if( zRO && sqlite3GetBoolean(zRO) ){
+          pShmNode->h = robust_open(zShmFilename, O_RDONLY,
+                                    (sStat.st_mode & 0777));
+          pShmNode->isReadonly = 1;
+        }
+        if( pShmNode->h<0 ){
+          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
+          goto shm_open_err;
+        }
       }
   
       /* Check to see if another process is holding the dead-man switch.
@@ -28031,11 +28406,12 @@ static int unixShmMap(
     while(pShmNode->nRegion<=iRegion){
       void *pMem;
       if( pShmNode->h>=0 ){
-        pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, 
+        pMem = mmap(0, szRegion,
+            pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, 
             MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
         );
         if( pMem==MAP_FAILED ){
-          rc = SQLITE_IOERR;
+          rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
           goto shmpage_out;
         }
       }else{
@@ -28057,6 +28433,7 @@ shmpage_out:
   }else{
     *pp = 0;
   }
+  if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
   sqlite3_mutex_leave(pShmNode->mutex);
   return rc;
 }
@@ -28910,6 +29287,11 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
 ** corresponding database file and sets *pMode to this value. Whenever 
 ** possible, WAL and journal files are created using the same permissions 
 ** as the associated database file.
+**
+** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
+** original filename is unavailable.  But 8_3_NAMES is only used for
+** FAT filesystems and permissions do not matter there, so just use
+** the default permissions.
 */
 static int findCreateFileMode(
   const char *zPath,              /* Path of file (possibly) being created */
@@ -28917,6 +29299,7 @@ static int findCreateFileMode(
   mode_t *pMode                   /* OUT: Permissions to open file with */
 ){
   int rc = SQLITE_OK;             /* Return Code */
+  *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
   if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
     char zDb[MAX_PATHNAME+1];     /* Database file path */
     int nDb;                      /* Number of valid bytes in zDb */
@@ -28928,15 +29311,15 @@ static int findCreateFileMode(
     **
     **   "<path to db>-journal"
     **   "<path to db>-wal"
-    **   "<path to db>-journal-NNNN"
-    **   "<path to db>-wal-NNNN"
+    **   "<path to db>-journalNN"
+    **   "<path to db>-walNN"
     **
-    ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are 
+    ** where NN is a 4 digit decimal number. The NN naming schemes are 
     ** used by the test_multiplex.c module.
     */
     nDb = sqlite3Strlen30(zPath) - 1; 
-    while( nDb>0 && zPath[nDb]!='l' ) nDb--;
-    nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7);
+    while( nDb>0 && zPath[nDb]!='-' ) nDb--;
+    if( nDb==0 ) return SQLITE_OK;
     memcpy(zDb, zPath, nDb);
     zDb[nDb] = '\0';
 
@@ -28947,8 +29330,6 @@ static int findCreateFileMode(
     }
   }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
     *pMode = 0600;
-  }else{
-    *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
   }
   return rc;
 }
@@ -31156,6 +31537,7 @@ struct winFile {
 #endif
 };
 
+
 /*
 ** Forward prototypes.
 */
@@ -31323,7 +31705,7 @@ SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){
 ** Convert UTF-8 to multibyte character string.  Space to hold the 
 ** returned string is obtained from malloc().
 */
-static char *utf8ToMbcs(const char *zFilename){
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){
   char *zFilenameMbcs;
   WCHAR *zTmpWide;
 
@@ -31336,6 +31718,109 @@ static char *utf8ToMbcs(const char *zFilename){
   return zFilenameMbcs;
 }
 
+
+/*
+** The return value of getLastErrorMsg
+** is zero if the error message fits in the buffer, or non-zero
+** otherwise (if the message was truncated).
+*/
+static int getLastErrorMsg(int nBuf, char *zBuf){
+  /* FormatMessage returns 0 on failure.  Otherwise it
+  ** returns the number of TCHARs written to the output
+  ** buffer, excluding the terminating null char.
+  */
+  DWORD error = GetLastError();
+  DWORD dwLen = 0;
+  char *zOut = 0;
+
+  if( isNT() ){
+    WCHAR *zTempWide = NULL;
+    dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                           NULL,
+                           error,
+                           0,
+                           (LPWSTR) &zTempWide,
+                           0,
+                           0);
+    if( dwLen > 0 ){
+      /* allocate a buffer and convert to UTF8 */
+      zOut = unicodeToUtf8(zTempWide);
+      /* free the system buffer allocated by FormatMessage */
+      LocalFree(zTempWide);
+    }
+/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
+** Since the ASCII version of these Windows API do not exist for WINCE,
+** it's important to not reference them for WINCE builds.
+*/
+#if SQLITE_OS_WINCE==0
+  }else{
+    char *zTemp = NULL;
+    dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                           NULL,
+                           error,
+                           0,
+                           (LPSTR) &zTemp,
+                           0,
+                           0);
+    if( dwLen > 0 ){
+      /* allocate a buffer and convert to UTF8 */
+      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+      /* free the system buffer allocated by FormatMessage */
+      LocalFree(zTemp);
+    }
+#endif
+  }
+  if( 0 == dwLen ){
+    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
+  }else{
+    /* copy a maximum of nBuf chars to output buffer */
+    sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
+    /* free the UTF8 buffer */
+    free(zOut);
+  }
+  return 0;
+}
+
+/*
+**
+** This function - winLogErrorAtLine() - is only ever called via the macro
+** winLogError().
+**
+** This routine is invoked after an error occurs in an OS function.
+** It logs a message using sqlite3_log() containing the current value of
+** error code and, if possible, the human-readable equivalent from 
+** FormatMessage.
+**
+** The first argument passed to the macro should be the error code that
+** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). 
+** The two subsequent arguments should be the name of the OS function that
+** failed and the the associated file-system path, if any.
+*/
+#define winLogError(a,b,c)     winLogErrorAtLine(a,b,c,__LINE__)
+static int winLogErrorAtLine(
+  int errcode,                    /* SQLite error code */
+  const char *zFunc,              /* Name of OS function that failed */
+  const char *zPath,              /* File path associated with error */
+  int iLine                       /* Source line number where error occurred */
+){
+  char zMsg[500];                 /* Human readable error text */
+  int i;                          /* Loop counter */
+  DWORD iErrno = GetLastError();  /* Error code */
+
+  zMsg[0] = 0;
+  getLastErrorMsg(sizeof(zMsg), zMsg);
+  assert( errcode!=SQLITE_OK );
+  if( zPath==0 ) zPath = "";
+  for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
+  zMsg[i] = 0;
+  sqlite3_log(errcode,
+      "os_win.c:%d: (%d) %s(%s) - %s",
+      iLine, iErrno, zFunc, zPath, zMsg
+  );
+
+  return errcode;
+}
+
 #if SQLITE_OS_WINCE
 /*************************************************************************
 ** This section contains code for WinCE only.
@@ -31412,6 +31897,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
   pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
   if (!pFile->hMutex){
     pFile->lastErrno = GetLastError();
+    winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
     free(zName);
     return FALSE;
   }
@@ -31443,6 +31929,7 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
     /* If mapping failed, close the shared memory handle and erase it */
     if (!pFile->shared){
       pFile->lastErrno = GetLastError();
+      winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename);
       CloseHandle(pFile->hShared);
       pFile->hShared = NULL;
     }
@@ -31688,6 +32175,7 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
   dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
   if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
     pFile->lastErrno = GetLastError();
+    winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath);
     return 1;
   }
 
@@ -31733,7 +32221,8 @@ static int winClose(sqlite3_file *id){
 #endif
   OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
   OpenCounter(-1);
-  return rc ? SQLITE_OK : SQLITE_IOERR;
+  return rc ? SQLITE_OK
+            : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath);
 }
 
 /*
@@ -31759,7 +32248,7 @@ static int winRead(
   }
   if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
     pFile->lastErrno = GetLastError();
-    return SQLITE_IOERR_READ;
+    return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
   }
   if( nRead<(DWORD)amt ){
     /* Unread parts of the buffer must be zero-filled */
@@ -31807,10 +32296,11 @@ static int winWrite(
   }
 
   if( rc ){
-    if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
+    if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
+       || ( pFile->lastErrno==ERROR_DISK_FULL )){
       return SQLITE_FULL;
     }
-    return SQLITE_IOERR_WRITE;
+    return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
   }
   return SQLITE_OK;
 }
@@ -31838,10 +32328,10 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
 
   /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
   if( seekWinFile(pFile, nByte) ){
-    rc = SQLITE_IOERR_TRUNCATE;
+    rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath);
   }else if( 0==SetEndOfFile(pFile->h) ){
     pFile->lastErrno = GetLastError();
-    rc = SQLITE_IOERR_TRUNCATE;
+    rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath);
   }
 
   OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
@@ -31863,6 +32353,7 @@ SQLITE_API int sqlite3_fullsync_count = 0;
 static int winSync(sqlite3_file *id, int flags){
 #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG)
   winFile *pFile = (winFile*)id;
+  BOOL rc;
 #else
   UNUSED_PARAMETER(id);
 #endif
@@ -31875,32 +32366,33 @@ static int winSync(sqlite3_file *id, int flags){
 
   OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
 
+  /* Unix cannot, but some systems may return SQLITE_FULL from here. This
+  ** line is to test that doing so does not cause any problems.
+  */
+  SimulateDiskfullError( return SQLITE_FULL );
+
 #ifndef SQLITE_TEST
   UNUSED_PARAMETER(flags);
 #else
-  if( flags & SQLITE_SYNC_FULL ){
+  if( (flags&0x0F)==SQLITE_SYNC_FULL ){
     sqlite3_fullsync_count++;
   }
   sqlite3_sync_count++;
 #endif
 
-  /* Unix cannot, but some systems may return SQLITE_FULL from here. This
-  ** line is to test that doing so does not cause any problems.
-  */
-  SimulateDiskfullError( return SQLITE_FULL );
-  SimulateIOError( return SQLITE_IOERR; );
-
   /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
   ** no-op
   */
 #ifdef SQLITE_NO_SYNC
   return SQLITE_OK;
 #else
-  if( FlushFileBuffers(pFile->h) ){
+  rc = FlushFileBuffers(pFile->h);
+  SimulateIOError( rc=FALSE );
+  if( rc ){
     return SQLITE_OK;
   }else{
     pFile->lastErrno = GetLastError();
-    return SQLITE_IOERR;
+    return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath);
   }
 #endif
 }
@@ -31921,7 +32413,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
      && ((error = GetLastError()) != NO_ERROR) )
   {
     pFile->lastErrno = error;
-    return SQLITE_IOERR_FSTAT;
+    return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath);
   }
   *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits;
   return SQLITE_OK;
@@ -31960,6 +32452,7 @@ static int getReadLock(winFile *pFile){
   }
   if( res == 0 ){
     pFile->lastErrno = GetLastError();
+    /* No need to log a failure to lock */
   }
   return res;
 }
@@ -31978,8 +32471,9 @@ static int unlockReadLock(winFile *pFile){
     res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0);
 #endif
   }
-  if( res == 0 ){
+  if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){
     pFile->lastErrno = GetLastError();
+    winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath);
   }
   return res;
 }
@@ -32180,7 +32674,7 @@ static int winUnlock(sqlite3_file *id, int locktype){
     if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
       /* This should never happen.  We should always be able to
       ** reacquire the read lock */
-      rc = SQLITE_IOERR_UNLOCK;
+      rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath);
     }
   }
   if( type>=RESERVED_LOCK ){
@@ -32495,6 +32989,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
   memset(pNew, 0, sizeof(*pNew));
   pNew->zFilename = (char*)&pNew[1];
   sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
+  sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); 
 
   /* Look to see if there is an existing winShmNode that can be used.
   ** If no matching winShmNode currently exists, create a new one.
@@ -32537,7 +33032,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
     if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
       rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
       if( rc!=SQLITE_OK ){
-        rc = SQLITE_IOERR_SHMOPEN;
+        rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath);
       }
     }
     if( rc==SQLITE_OK ){
@@ -32796,7 +33291,7 @@ static int winShmMap(
     */
     rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz);
     if( rc!=SQLITE_OK ){
-      rc = SQLITE_IOERR_SHMSIZE;
+      rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath);
       goto shmpage_out;
     }
 
@@ -32810,7 +33305,7 @@ static int winShmMap(
       if( !isWrite ) goto shmpage_out;
       rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte);
       if( rc!=SQLITE_OK ){
-        rc = SQLITE_IOERR_SHMSIZE;
+        rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath);
         goto shmpage_out;
       }
     }
@@ -32847,7 +33342,7 @@ static int winShmMap(
       }
       if( !pMap ){
         pShmNode->lastErrno = GetLastError();
-        rc = SQLITE_IOERR;
+        rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
         if( hMap ) CloseHandle(hMap);
         goto shmpage_out;
       }
@@ -32929,7 +33424,7 @@ static void *convertUtf8Filename(const char *zFilename){
 */
 #if SQLITE_OS_WINCE==0
   }else{
-    zConverted = utf8ToMbcs(zFilename);
+    zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
 #endif
   }
   /* caller will handle out of memory */
@@ -33009,68 +33504,6 @@ static int getTempname(int nBuf, char *zBuf){
   return SQLITE_OK; 
 }
 
-/*
-** The return value of getLastErrorMsg
-** is zero if the error message fits in the buffer, or non-zero
-** otherwise (if the message was truncated).
-*/
-static int getLastErrorMsg(int nBuf, char *zBuf){
-  /* FormatMessage returns 0 on failure.  Otherwise it
-  ** returns the number of TCHARs written to the output
-  ** buffer, excluding the terminating null char.
-  */
-  DWORD error = GetLastError();
-  DWORD dwLen = 0;
-  char *zOut = 0;
-
-  if( isNT() ){
-    WCHAR *zTempWide = NULL;
-    dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-                           NULL,
-                           error,
-                           0,
-                           (LPWSTR) &zTempWide,
-                           0,
-                           0);
-    if( dwLen > 0 ){
-      /* allocate a buffer and convert to UTF8 */
-      zOut = unicodeToUtf8(zTempWide);
-      /* free the system buffer allocated by FormatMessage */
-      LocalFree(zTempWide);
-    }
-/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. 
-** Since the ASCII version of these Windows API do not exist for WINCE,
-** it's important to not reference them for WINCE builds.
-*/
-#if SQLITE_OS_WINCE==0
-  }else{
-    char *zTemp = NULL;
-    dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-                           NULL,
-                           error,
-                           0,
-                           (LPSTR) &zTemp,
-                           0,
-                           0);
-    if( dwLen > 0 ){
-      /* allocate a buffer and convert to UTF8 */
-      zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
-      /* free the system buffer allocated by FormatMessage */
-      LocalFree(zTemp);
-    }
-#endif
-  }
-  if( 0 == dwLen ){
-    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error);
-  }else{
-    /* copy a maximum of nBuf chars to output buffer */
-    sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
-    /* free the UTF8 buffer */
-    free(zOut);
-  }
-  return 0;
-}
-
 /*
 ** Open a file.
 */
@@ -33242,6 +33675,7 @@ static int winOpen(
 
   if( h==INVALID_HANDLE_VALUE ){
     pFile->lastErrno = GetLastError();
+    winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
     free(zConverted);
     if( isReadWrite ){
       return winOpen(pVfs, zName, id, 
@@ -33345,7 +33779,8 @@ static int winDelete(
          "ok" : "failed" ));
  
   return (   (rc == INVALID_FILE_ATTRIBUTES) 
-          && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
+          && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK :
+                 winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
 }
 
 /*
@@ -33385,6 +33820,7 @@ static int winAccess(
       }
     }else{
       if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
+        winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
         free(zConverted);
         return SQLITE_IOERR_ACCESS;
       }else{
@@ -33449,6 +33885,13 @@ static int winFullPathname(
   void *zConverted;
   char *zOut;
 
+  /* If this path name begins with "/X:", where "X" is any alphabetic
+  ** character, discard the initial "/" from the pathname.
+  */
+  if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){
+    zRelative++;
+  }
+
   /* It's odd to simulate an io-error here, but really this is just
   ** using the io-error infrastructure to test that SQLite handles this
   ** function failing. This function could fail if, for example, the
@@ -34489,6 +34932,13 @@ SQLITE_PRIVATE int sqlite3PcacheFetch(
     }
     if( pPg ){
       int rc;
+#ifdef SQLITE_LOG_CACHE_SPILL
+      sqlite3_log(SQLITE_FULL, 
+                  "spill page %d making room for %d - cache used: %d/%d",
+                  pPg->pgno, pgno,
+                  sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
+                  pCache->nMax);
+#endif
       rc = pCache->xStress(pCache->pStress, pPg);
       if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
         return rc;
@@ -35399,7 +35849,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int bPurgeable){
       pGroup = (PGroup*)&pCache[1];
       pGroup->mxPinned = 10;
     }else{
-      pGroup = &pcache1_g.grp;
+      pGroup = &pcache1.grp;
     }
     pCache->pGroup = pGroup;
     pCache->szPage = szPage;
@@ -36260,6 +36710,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 
 #ifdef SQLITE_OMIT_WAL
 # define sqlite3WalOpen(x,y,z)                   0
+# define sqlite3WalLimit(x,y)
 # define sqlite3WalClose(w,x,y,z)                0
 # define sqlite3WalBeginReadTransaction(y,z)     0
 # define sqlite3WalEndReadTransaction(z)
@@ -36285,9 +36736,12 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 typedef struct Wal Wal;
 
 /* Open and close a connection to a write-ahead log. */
-SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**);
+SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
 SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
 
+/* Set the limiting size of a WAL file. */
+SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
+
 /* Used by readers to open (lock) and close (unlock) a snapshot.  A 
 ** snapshot is like a read-transaction.  It is the state of the database
 ** at an instant in time.  sqlite3WalOpenSnapshot gets a read lock and
@@ -40636,6 +41090,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   int noReadlock = (flags & PAGER_NO_READLOCK)!=0;  /* True to omit read-lock */
   int pcacheSize = sqlite3PcacheSize();       /* Bytes to allocate for PCache */
   u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;  /* Default page size */
+  const char *zUri = 0;    /* URI args to copy */
+  int nUri = 0;            /* Number of bytes of URI args at *zUri */
 
   /* Figure out how much space is required for each journal file-handle
   ** (there are two of them, the main journal and the sub-journal). This
@@ -40666,6 +41122,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   ** leave both nPathname and zPathname set to 0.
   */
   if( zFilename && zFilename[0] ){
+    const char *z;
     nPathname = pVfs->mxPathname+1;
     zPathname = sqlite3Malloc(nPathname*2);
     if( zPathname==0 ){
@@ -40674,6 +41131,12 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
     zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
     rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
     nPathname = sqlite3Strlen30(zPathname);
+    z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
+    while( *z ){
+      z += sqlite3Strlen30(z)+1;
+      z += sqlite3Strlen30(z)+1;
+    }
+    nUri = &z[1] - zUri;
     if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){
       /* This branch is taken when the journal path required by
       ** the database being opened will be more than pVfs->mxPathname
@@ -40706,7 +41169,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
     ROUND8(pcacheSize) +           /* PCache object */
     ROUND8(pVfs->szOsFile) +       /* The main db file */
     journalFileSize * 2 +          /* The two journal files */ 
-    nPathname + 1 +                /* zFilename */
+    nPathname + 1 + nUri +         /* zFilename */
     nPathname + 8 + 1              /* zJournal */
 #ifndef SQLITE_OMIT_WAL
     + nPathname + 4 + 1              /* zWal */
@@ -40728,14 +41191,17 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
   if( zPathname ){
     assert( nPathname>0 );
-    pPager->zJournal =   (char*)(pPtr += nPathname + 1);
+    pPager->zJournal =   (char*)(pPtr += nPathname + 1 + nUri);
     memcpy(pPager->zFilename, zPathname, nPathname);
+    memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
     memcpy(pPager->zJournal, zPathname, nPathname);
     memcpy(&pPager->zJournal[nPathname], "-journal", 8);
+    sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal);
 #ifndef SQLITE_OMIT_WAL
     pPager->zWal = &pPager->zJournal[nPathname+8+1];
     memcpy(pPager->zWal, zPathname, nPathname);
     memcpy(&pPager->zWal[nPathname], "-wal", 4);
+    sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
 #endif
     sqlite3_free(zPathname);
   }
@@ -42072,11 +42538,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
   }else{
     if( pagerUseWal(pPager) ){
       PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
-      if( pList ){
+      PgHdr *pPageOne = 0;
+      if( pList==0 ){
+        /* Must have at least one page for the WAL commit flag.
+        ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
+        rc = sqlite3PagerGet(pPager, 1, &pPageOne);
+        pList = pPageOne;
+        pList->pDirty = 0;
+      }
+      assert( rc==SQLITE_OK );
+      if( ALWAYS(pList) ){
         rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, 
             (pPager->fullSync ? pPager->syncFlags : 0)
         );
       }
+      sqlite3PagerUnref(pPageOne);
       if( rc==SQLITE_OK ){
         sqlite3PcacheCleanAll(pPager->pPCache);
       }
@@ -42934,6 +43410,7 @@ SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
 SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
   if( iLimit>=-1 ){
     pPager->journalSizeLimit = iLimit;
+    sqlite3WalLimit(pPager->pWal, iLimit);
   }
   return pPager->journalSizeLimit;
 }
@@ -43025,7 +43502,8 @@ static int pagerOpenWal(Pager *pPager){
   */
   if( rc==SQLITE_OK ){
     rc = sqlite3WalOpen(pPager->pVfs, 
-        pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal
+        pPager->fd, pPager->zWal, pPager->exclusiveMode,
+        pPager->journalSizeLimit, &pPager->pWal
     );
   }
 
@@ -43557,6 +44035,7 @@ struct Wal {
   sqlite3_file *pDbFd;       /* File handle for the database file */
   sqlite3_file *pWalFd;      /* File handle for WAL file */
   u32 iCallback;             /* Value to pass to log callback (or 0) */
+  i64 mxWalSize;             /* Truncate WAL to this size upon reset */
   int nWiData;               /* Size of array apWiData */
   volatile u32 **apWiData;   /* Pointer to wal-index content in memory */
   u32 szPage;                /* Database page size */
@@ -43564,7 +44043,7 @@ struct Wal {
   u8 exclusiveMode;          /* Non-zero if connection is in exclusive mode */
   u8 writeLock;              /* True if in a write transaction */
   u8 ckptLock;               /* True if holding a checkpoint lock */
-  u8 readOnly;               /* True if the WAL file is open read-only */
+  u8 readOnly;               /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
   WalIndexHdr hdr;           /* Wal-index header for current transaction */
   const char *zWalName;      /* Name of WAL file */
   u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
@@ -43580,6 +44059,13 @@ struct Wal {
 #define WAL_EXCLUSIVE_MODE  1     
 #define WAL_HEAPMEMORY_MODE 2
 
+/*
+** Possible values for WAL.readOnly
+*/
+#define WAL_RDWR        0    /* Normal read/write connection */
+#define WAL_RDONLY      1    /* The WAL file is readonly */
+#define WAL_SHM_RDONLY  2    /* The SHM file is readonly */
+
 /*
 ** Each page of the wal-index mapping contains a hash-table made up of
 ** an array of HASHTABLE_NSLOT elements of the following type.
@@ -43673,6 +44159,10 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
       rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
           pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
       );
+      if( rc==SQLITE_READONLY ){
+        pWal->readOnly |= WAL_SHM_RDONLY;
+        rc = SQLITE_OK;
+      }
     }
   }
 
@@ -44379,6 +44869,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   sqlite3_file *pDbFd,            /* The open database file */
   const char *zWalName,           /* Name of the WAL file */
   int bNoShm,                     /* True to run in heap-memory mode */
+  i64 mxWalSize,                  /* Truncate WAL to this size on reset */
   Wal **ppWal                     /* OUT: Allocated Wal handle */
 ){
   int rc;                         /* Return Code */
@@ -44411,6 +44902,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   pRet->pWalFd = (sqlite3_file *)&pRet[1];
   pRet->pDbFd = pDbFd;
   pRet->readLock = -1;
+  pRet->mxWalSize = mxWalSize;
   pRet->zWalName = zWalName;
   pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
 
@@ -44418,7 +44910,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
   rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
   if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
-    pRet->readOnly = 1;
+    pRet->readOnly = WAL_RDONLY;
   }
 
   if( rc!=SQLITE_OK ){
@@ -44432,6 +44924,13 @@ SQLITE_PRIVATE int sqlite3WalOpen(
   return rc;
 }
 
+/*
+** Change the size to which the WAL file is trucated on each reset.
+*/
+SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
+  if( pWal ) pWal->mxWalSize = iLimit;
+}
+
 /*
 ** Find the smallest page number out of all pages held in the WAL that
 ** has not been returned by any prior invocation of this method on the
@@ -45052,21 +45551,28 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
   ** with a writer.  So get a WRITE lock and try again.
   */
   assert( badHdr==0 || pWal->writeLock==0 );
-  if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
-    pWal->writeLock = 1;
-    if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
-      badHdr = walIndexTryHdr(pWal, pChanged);
-      if( badHdr ){
-        /* If the wal-index header is still malformed even while holding
-        ** a WRITE lock, it can only mean that the header is corrupted and
-        ** needs to be reconstructed.  So run recovery to do exactly that.
-        */
-        rc = walIndexRecover(pWal);
-        *pChanged = 1;
+  if( badHdr ){
+    if( pWal->readOnly & WAL_SHM_RDONLY ){
+      if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
+        walUnlockShared(pWal, WAL_WRITE_LOCK);
+        rc = SQLITE_READONLY_RECOVERY;
+      }
+    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+      pWal->writeLock = 1;
+      if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+        badHdr = walIndexTryHdr(pWal, pChanged);
+        if( badHdr ){
+          /* If the wal-index header is still malformed even while holding
+          ** a WRITE lock, it can only mean that the header is corrupted and
+          ** needs to be reconstructed.  So run recovery to do exactly that.
+          */
+          rc = walIndexRecover(pWal);
+          *pChanged = 1;
+        }
       }
+      pWal->writeLock = 0;
+      walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
     }
-    pWal->writeLock = 0;
-    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
   }
 
   /* If the header is read successfully, check the version number to make
@@ -45253,7 +45759,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
   }
   /* There was once an "if" here. The extra "{" is to preserve indentation. */
   {
-    if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){
+    if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
+    ){
       for(i=1; i<WAL_NREADER; i++){
         rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
         if( rc==SQLITE_OK ){
@@ -45267,8 +45775,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
       }
     }
     if( mxI==0 ){
-      assert( rc==SQLITE_BUSY );
-      return WAL_RETRY;
+      assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
+      return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
     }
 
     rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
@@ -45667,6 +46175,24 @@ static int walRestartLog(Wal *pWal){
         */
         int i;                    /* Loop counter */
         u32 *aSalt = pWal->hdr.aSalt;       /* Big-endian salt values */
+
+        /* Limit the size of WAL file if the journal_size_limit PRAGMA is
+        ** set to a non-negative value.  Log errors encountered
+        ** during the truncation attempt. */
+        if( pWal->mxWalSize>=0 ){
+          i64 sz;
+          int rx;
+          sqlite3BeginBenignMalloc();
+          rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
+          if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){
+            rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize);
+          }
+          sqlite3EndBenignMalloc();
+          if( rx ){
+            sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
+          }
+        }
+
         pWal->nCkpt++;
         pWal->hdr.mxFrame = 0;
         sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
@@ -45892,6 +46418,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
   assert( pWal->ckptLock==0 );
   assert( pWal->writeLock==0 );
 
+  if( pWal->readOnly ) return SQLITE_READONLY;
   WALTRACE(("WAL%p: checkpoint begins\n", pWal));
   rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
   if( rc ){
@@ -47772,6 +48299,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
     *pRC = SQLITE_CORRUPT_BKPT;
     goto ptrmap_exit;
   }
+  assert( offset <= (int)pBt->usableSize-5 );
   pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
 
   if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
@@ -47811,6 +48339,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
   pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
 
   offset = PTRMAP_PTROFFSET(iPtrmap, key);
+  if( offset<0 ){
+    sqlite3PagerUnref(pDbPage);
+    return SQLITE_CORRUPT_BKPT;
+  }
+  assert( offset <= (int)pBt->usableSize-5 );
   assert( pEType!=0 );
   *pEType = pPtrmap[offset];
   if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
@@ -47835,6 +48368,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
 */
 #define findCell(P,I) \
   ((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)])))
+#define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I)))))
+
 
 /*
 ** This a more complex version of findCell() that works for
@@ -48672,13 +49207,13 @@ static int btreeInvokeBusyHandler(void *pArg){
 ** to problems with locking.
 */
 SQLITE_PRIVATE int sqlite3BtreeOpen(
+  sqlite3_vfs *pVfs,      /* VFS to use for this b-tree */
   const char *zFilename,  /* Name of the file containing the BTree database */
   sqlite3 *db,            /* Associated database handle */
   Btree **ppBtree,        /* Pointer to new Btree object written here */
   int flags,              /* Options */
   int vfsFlags            /* Flags passed through to sqlite3_vfs.xOpen() */
 ){
-  sqlite3_vfs *pVfs;             /* The VFS to use for this btree */
   BtShared *pBt = 0;             /* Shared part of btree structure */
   Btree *p;                      /* Handle to return */
   sqlite3_mutex *mutexOpen = 0;  /* Prevents a race condition. Ticket #3537 */
@@ -48700,6 +49235,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
 #endif
 
   assert( db!=0 );
+  assert( pVfs!=0 );
   assert( sqlite3_mutex_held(db->mutex) );
   assert( (flags&0xff)==flags );   /* flags fit in 8 bits */
 
@@ -48718,7 +49254,6 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
   if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
     vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
   }
-  pVfs = db->pVfs;
   p = sqlite3MallocZero(sizeof(Btree));
   if( !p ){
     return SQLITE_NOMEM;
@@ -51429,7 +51964,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
   }
   assert( pCur->apPage[0]->intKey || pIdxKey );
   for(;;){
-    int lwr, upr;
+    int lwr, upr, idx;
     Pgno chldPg;
     MemPage *pPage = pCur->apPage[pCur->iPage];
     int c;
@@ -51445,14 +51980,14 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
     lwr = 0;
     upr = pPage->nCell-1;
     if( biasRight ){
-      pCur->aiIdx[pCur->iPage] = (u16)upr;
+      pCur->aiIdx[pCur->iPage] = (u16)(idx = upr);
     }else{
-      pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2);
+      pCur->aiIdx[pCur->iPage] = (u16)(idx = (upr+lwr)/2);
     }
     for(;;){
-      int idx = pCur->aiIdx[pCur->iPage]; /* Index of current cell in pPage */
       u8 *pCell;                          /* Pointer to current cell in pPage */
 
+      assert( idx==pCur->aiIdx[pCur->iPage] );
       pCur->info.nSize = 0;
       pCell = findCell(pPage, idx) + pPage->childPtrSize;
       if( pPage->intKey ){
@@ -51535,7 +52070,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
       if( lwr>upr ){
         break;
       }
-      pCur->aiIdx[pCur->iPage] = (u16)((lwr+upr)/2);
+      pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
     }
     assert( lwr==upr+1 );
     assert( pPage->isInit );
@@ -52368,10 +52903,10 @@ static int fillInCell(
 ** "sz" must be the number of bytes in the cell.
 */
 static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
-  int i;          /* Loop counter */
   u32 pc;         /* Offset to cell content of cell being deleted */
   u8 *data;       /* pPage->aData */
   u8 *ptr;        /* Used to move bytes around within data[] */
+  u8 *endPtr;     /* End of loop */
   int rc;         /* The return code */
   int hdr;        /* Beginning of the header.  0 most pages.  100 page 1 */
 
@@ -52396,9 +52931,11 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
     *pRC = rc;
     return;
   }
-  for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
-    ptr[0] = ptr[2];
-    ptr[1] = ptr[3];
+  endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2];
+  assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 );  /* ptr is always 2-byte aligned */
+  while( ptr<endPtr ){
+    *(u16*)ptr = *(u16*)&ptr[2];
+    ptr += 2;
   }
   pPage->nCell--;
   put2byte(&data[hdr+3], pPage->nCell);
@@ -52438,6 +52975,7 @@ static void insertCell(
   int cellOffset;   /* Address of first cell pointer in data[] */
   u8 *data;         /* The content of the whole page */
   u8 *ptr;          /* Used for moving information around in data[] */
+  u8 *endPtr;       /* End of the loop */
 
   int nSkip = (iChild ? 4 : 0);
 
@@ -52488,9 +53026,12 @@ static void insertCell(
     if( iChild ){
       put4byte(&data[idx], iChild);
     }
-    for(j=end, ptr=&data[j]; j>ins; j-=2, ptr-=2){
-      ptr[0] = ptr[-2];
-      ptr[1] = ptr[-1];
+    ptr = &data[end];
+    endPtr = &data[ins];
+    assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 );  /* ptr is always 2-byte aligned */
+    while( ptr>endPtr ){
+      *(u16*)ptr = *(u16*)&ptr[-2];
+      ptr -= 2;
     }
     put2byte(&data[ins], idx);
     put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
@@ -52535,10 +53076,11 @@ static void assemblePage(
   pCellptr = &data[pPage->cellOffset + nCell*2];
   cellbody = nUsable;
   for(i=nCell-1; i>=0; i--){
+    u16 sz = aSize[i];
     pCellptr -= 2;
-    cellbody -= aSize[i];
+    cellbody -= sz;
     put2byte(pCellptr, cellbody);
-    memcpy(&data[cellbody], apCell[i], aSize[i]);
+    memcpy(&data[cellbody], apCell[i], sz);
   }
   put2byte(&data[hdr+3], nCell);
   put2byte(&data[hdr+5], cellbody);
@@ -52992,12 +53534,24 @@ static int balance_nonroot(
     memcpy(pOld->aData, apOld[i]->aData, pBt->pageSize);
 
     limit = pOld->nCell+pOld->nOverflow;
-    for(j=0; j<limit; j++){
-      assert( nCell<nMaxCells );
-      apCell[nCell] = findOverflowCell(pOld, j);
-      szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
-      nCell++;
-    }
+    if( pOld->nOverflow>0 ){
+      for(j=0; j<limit; j++){
+        assert( nCell<nMaxCells );
+        apCell[nCell] = findOverflowCell(pOld, j);
+        szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
+        nCell++;
+      }
+    }else{
+      u8 *aData = pOld->aData;
+      u16 maskPage = pOld->maskPage;
+      u16 cellOffset = pOld->cellOffset;
+      for(j=0; j<limit; j++){
+        assert( nCell<nMaxCells );
+        apCell[nCell] = findCellv2(aData, maskPage, cellOffset, j);
+        szCell[nCell] = cellSizePtr(pOld, apCell[nCell]);
+        nCell++;
+      }
+    }       
     if( i<nOld-1 && !leafData){
       u16 sz = (u16)szNew[i];
       u8 *pTemp;
@@ -57146,13 +57700,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
   pOp->p3 = p3;
   pOp->p4.p = 0;
   pOp->p4type = P4_NOTUSED;
-  p->expired = 0;
-  if( op==OP_ParseSchema ){
-    /* Any program that uses the OP_ParseSchema opcode needs to lock
-    ** all btrees. */
-    int j;
-    for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
-  }
 #ifdef SQLITE_DEBUG
   pOp->zComment = 0;
   if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
@@ -57191,6 +57738,20 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
   return addr;
 }
 
+/*
+** Add an OP_ParseSchema opcode.  This routine is broken out from
+** sqlite3VdbeAddOp4() since it needs to also local all btrees.
+**
+** The zWhere string must have been obtained from sqlite3_malloc().
+** This routine will take ownership of the allocated memory.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
+  int j;
+  int addr = sqlite3VdbeAddOp3(p, OP_ParseSchema, iDb, 0, 0);
+  sqlite3VdbeChangeP4(p, addr, zWhere, P4_DYNAMIC);
+  for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
+}
+
 /*
 ** Add an opcode that includes the p4 value as an integer.
 */
@@ -58381,44 +58942,88 @@ static void *allocSpace(
 }
 
 /*
-** Prepare a virtual machine for execution.  This involves things such
+** Rewind the VDBE back to the beginning in preparation for
+** running it.
+*/
+SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+  int i;
+#endif
+  assert( p!=0 );
+  assert( p->magic==VDBE_MAGIC_INIT );
+
+  /* There should be at least one opcode.
+  */
+  assert( p->nOp>0 );
+
+  /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
+  p->magic = VDBE_MAGIC_RUN;
+
+#ifdef SQLITE_DEBUG
+  for(i=1; i<p->nMem; i++){
+    assert( p->aMem[i].db==p->db );
+  }
+#endif
+  p->pc = -1;
+  p->rc = SQLITE_OK;
+  p->errorAction = OE_Abort;
+  p->magic = VDBE_MAGIC_RUN;
+  p->nChange = 0;
+  p->cacheCtr = 1;
+  p->minWriteFileFormat = 255;
+  p->iStatement = 0;
+  p->nFkConstraint = 0;
+#ifdef VDBE_PROFILE
+  for(i=0; i<p->nOp; i++){
+    p->aOp[i].cnt = 0;
+    p->aOp[i].cycles = 0;
+  }
+#endif
+}
+
+/*
+** Prepare a virtual machine for execution for the first time after
+** creating the virtual machine.  This involves things such
 ** as allocating stack space and initializing the program counter.
 ** After the VDBE has be prepped, it can be executed by one or more
 ** calls to sqlite3VdbeExec().  
 **
-** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
-** VDBE_MAGIC_RUN.
+** This function may be called exact once on a each virtual machine.
+** After this routine is called the VM has been "packaged" and is ready
+** to run.  After this routine is called, futher calls to 
+** sqlite3VdbeAddOp() functions are prohibited.  This routine disconnects
+** the Vdbe from the Parse object that helped generate it so that the
+** the Vdbe becomes an independent entity and the Parse object can be
+** destroyed.
 **
-** This function may be called more than once on a single virtual machine.
-** The first call is made while compiling the SQL statement. Subsequent
-** calls are made as part of the process of resetting a statement to be
-** re-executed (from a call to sqlite3_reset()). The nVar, nMem, nCursor 
-** and isExplain parameters are only passed correct values the first time
-** the function is called. On subsequent calls, from sqlite3_reset(), nVar
-** is passed -1 and nMem, nCursor and isExplain are all passed zero.
+** Use the sqlite3VdbeRewind() procedure to restore a virtual machine back
+** to its initial state after it has been run.
 */
 SQLITE_PRIVATE void sqlite3VdbeMakeReady(
   Vdbe *p,                       /* The VDBE */
-  int nVar,                      /* Number of '?' see in the SQL statement */
-  int nMem,                      /* Number of memory cells to allocate */
-  int nCursor,                   /* Number of cursors to allocate */
-  int nArg,                      /* Maximum number of args in SubPrograms */
-  int isExplain,                 /* True if the EXPLAIN keywords is present */
-  int usesStmtJournal            /* True to set Vdbe.usesStmtJournal */
+  Parse *pParse                  /* Parsing context */
 ){
-  int n;
-  sqlite3 *db = p->db;
+  sqlite3 *db;                   /* The database connection */
+  int nVar;                      /* Number of parameters */
+  int nMem;                      /* Number of VM memory registers */
+  int nCursor;                   /* Number of cursors required */
+  int nArg;                      /* Number of arguments in subprograms */
+  int n;                         /* Loop counter */
+  u8 *zCsr;                      /* Memory available for allocation */
+  u8 *zEnd;                      /* First byte past allocated memory */
+  int nByte;                     /* How much extra memory is needed */
 
   assert( p!=0 );
-  assert( p->magic==VDBE_MAGIC_INIT );
-
-  /* There should be at least one opcode.
-  */
   assert( p->nOp>0 );
-
-  /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
-  p->magic = VDBE_MAGIC_RUN;
-
+  assert( pParse!=0 );
+  assert( p->magic==VDBE_MAGIC_INIT );
+  db = p->db;
+  assert( db->mallocFailed==0 );
+  nVar = pParse->nVar;
+  nMem = pParse->nMem;
+  nCursor = pParse->nTab;
+  nArg = pParse->nMaxArg;
+  
   /* For each cursor required, also allocate a memory cell. Memory
   ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
   ** the vdbe program. Instead they are used to allocate space for
@@ -58431,91 +59036,69 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
   nMem += nCursor;
 
   /* Allocate space for memory registers, SQL variables, VDBE cursors and 
-  ** an array to marshal SQL function arguments in. This is only done the
-  ** first time this function is called for a given VDBE, not when it is
-  ** being called from sqlite3_reset() to reset the virtual machine.
-  */
-  if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){
-    u8 *zCsr = (u8 *)&p->aOp[p->nOp];       /* Memory avaliable for alloation */
-    u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc];  /* First byte past available mem */
-    int nByte;                              /* How much extra memory needed */
-
-    resolveP2Values(p, &nArg);
-    p->usesStmtJournal = (u8)usesStmtJournal;
-    if( isExplain && nMem<10 ){
-      nMem = 10;
-    }
-    memset(zCsr, 0, zEnd-zCsr);
-    zCsr += (zCsr - (u8*)0)&7;
-    assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
-
-    /* Memory for registers, parameters, cursor, etc, is allocated in two
-    ** passes.  On the first pass, we try to reuse unused space at the 
-    ** end of the opcode array.  If we are unable to satisfy all memory
-    ** requirements by reusing the opcode array tail, then the second
-    ** pass will fill in the rest using a fresh allocation.  
-    **
-    ** This two-pass approach that reuses as much memory as possible from
-    ** the leftover space at the end of the opcode array can significantly
-    ** reduce the amount of memory held by a prepared statement.
-    */
-    do {
-      nByte = 0;
-      p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
-      p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
-      p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
-      p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
-      p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
-                            &zCsr, zEnd, &nByte);
-      if( nByte ){
-        p->pFree = sqlite3DbMallocZero(db, nByte);
-      }
-      zCsr = p->pFree;
-      zEnd = &zCsr[nByte];
-    }while( nByte && !db->mallocFailed );
+  ** an array to marshal SQL function arguments in.
+  */
+  zCsr = (u8*)&p->aOp[p->nOp];       /* Memory avaliable for allocation */
+  zEnd = (u8*)&p->aOp[p->nOpAlloc];  /* First byte past end of zCsr[] */
 
-    p->nCursor = (u16)nCursor;
-    if( p->aVar ){
-      p->nVar = (ynVar)nVar;
-      for(n=0; n<nVar; n++){
-        p->aVar[n].flags = MEM_Null;
-        p->aVar[n].db = db;
-      }
+  resolveP2Values(p, &nArg);
+  p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
+  if( pParse->explain && nMem<10 ){
+    nMem = 10;
+  }
+  memset(zCsr, 0, zEnd-zCsr);
+  zCsr += (zCsr - (u8*)0)&7;
+  assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
+  p->expired = 0;
+
+  /* Memory for registers, parameters, cursor, etc, is allocated in two
+  ** passes.  On the first pass, we try to reuse unused space at the 
+  ** end of the opcode array.  If we are unable to satisfy all memory
+  ** requirements by reusing the opcode array tail, then the second
+  ** pass will fill in the rest using a fresh allocation.  
+  **
+  ** This two-pass approach that reuses as much memory as possible from
+  ** the leftover space at the end of the opcode array can significantly
+  ** reduce the amount of memory held by a prepared statement.
+  */
+  do {
+    nByte = 0;
+    p->aMem = allocSpace(p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte);
+    p->aVar = allocSpace(p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte);
+    p->apArg = allocSpace(p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte);
+    p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
+    p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
+                          &zCsr, zEnd, &nByte);
+    if( nByte ){
+      p->pFree = sqlite3DbMallocZero(db, nByte);
     }
-    if( p->aMem ){
-      p->aMem--;                      /* aMem[] goes from 1..nMem */
-      p->nMem = nMem;                 /*       not from 0..nMem-1 */
-      for(n=1; n<=nMem; n++){
-        p->aMem[n].flags = MEM_Null;
-        p->aMem[n].db = db;
-      }
+    zCsr = p->pFree;
+    zEnd = &zCsr[nByte];
+  }while( nByte && !db->mallocFailed );
+
+  p->nCursor = (u16)nCursor;
+  if( p->aVar ){
+    p->nVar = (ynVar)nVar;
+    for(n=0; n<nVar; n++){
+      p->aVar[n].flags = MEM_Null;
+      p->aVar[n].db = db;
     }
   }
-#ifdef SQLITE_DEBUG
-  for(n=1; n<p->nMem; n++){
-    assert( p->aMem[n].db==db );
+  if( p->azVar ){
+    p->nzVar = pParse->nzVar;
+    memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
+    memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
   }
-#endif
-
-  p->pc = -1;
-  p->rc = SQLITE_OK;
-  p->errorAction = OE_Abort;
-  p->explain |= isExplain;
-  p->magic = VDBE_MAGIC_RUN;
-  p->nChange = 0;
-  p->cacheCtr = 1;
-  p->minWriteFileFormat = 255;
-  p->iStatement = 0;
-  p->nFkConstraint = 0;
-#ifdef VDBE_PROFILE
-  {
-    int i;
-    for(i=0; i<p->nOp; i++){
-      p->aOp[i].cnt = 0;
-      p->aOp[i].cycles = 0;
+  if( p->aMem ){
+    p->aMem--;                      /* aMem[] goes from 1..nMem */
+    p->nMem = nMem;                 /*       not from 0..nMem-1 */
+    for(n=1; n<=nMem; n++){
+      p->aMem[n].flags = MEM_Null;
+      p->aMem[n].db = db;
     }
   }
-#endif
+  p->explain = pParse->explain;
+  sqlite3VdbeRewind(p);
 }
 
 /*
@@ -58789,6 +59372,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
       if( !zMaster ){
         return SQLITE_NOMEM;
       }
+      sqlite3FileSuffix3(zMainFile, zMaster);
       rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
     }while( rc==SQLITE_OK && res );
     if( rc==SQLITE_OK ){
@@ -59003,6 +59587,15 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
     db->nStatement--;
     p->iStatement = 0;
 
+    if( rc==SQLITE_OK ){
+      if( eOp==SAVEPOINT_ROLLBACK ){
+        rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
+      }
+      if( rc==SQLITE_OK ){
+        rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
+      }
+    }
+
     /* If the statement transaction is being rolled back, also restore the 
     ** database handles deferred constraint counter to the value it had when 
     ** the statement transaction was opened.  */
@@ -59182,17 +59775,11 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
     ** do so. If this operation returns an error, and the current statement
     ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the
     ** current statement error code.
-    **
-    ** Note that sqlite3VdbeCloseStatement() can only fail if eStatementOp
-    ** is SAVEPOINT_ROLLBACK.  But if p->rc==SQLITE_OK then eStatementOp
-    ** must be SAVEPOINT_RELEASE.  Hence the NEVER(p->rc==SQLITE_OK) in 
-    ** the following code.
     */
     if( eStatementOp ){
       rc = sqlite3VdbeCloseStatement(p, eStatementOp);
       if( rc ){
-        assert( eStatementOp==SAVEPOINT_ROLLBACK );
-        if( NEVER(p->rc==SQLITE_OK) || p->rc==SQLITE_CONSTRAINT ){
+        if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
           p->rc = rc;
           sqlite3DbFree(db, p->zErrMsg);
           p->zErrMsg = 0;
@@ -59385,6 +59972,7 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
 */
 SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
   SubProgram *pSub, *pNext;
+  int i;
   assert( p->db==0 || p->db==db );
   releaseMemArray(p->aVar, p->nVar);
   releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
@@ -59393,6 +59981,7 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
     vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
     sqlite3DbFree(db, pSub);
   }
+  for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
   vdbeFreeOpArray(db, p->aOp, p->nOp);
   sqlite3DbFree(db, p->aLabel);
   sqlite3DbFree(db, p->aColName);
@@ -59838,7 +60427,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
     idx += getVarint32(&aKey[idx], serial_type);
     pMem->enc = pKeyInfo->enc;
     pMem->db = pKeyInfo->db;
-    pMem->flags = 0;
+    /* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
     pMem->zMalloc = 0;
     d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
     pMem++;
@@ -59853,6 +60442,7 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeRecordUnpack(
 ** This routine destroys a UnpackedRecord object.
 */
 SQLITE_PRIVATE void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
+#ifdef SQLITE_DEBUG
   int i;
   Mem *pMem;
 
@@ -59866,6 +60456,7 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
     */
     if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem);
   }
+#endif
   if( p->flags & UNPACKED_NEED_FREE ){
     sqlite3DbFree(p->pKeyInfo->db, p);
   }
@@ -59919,7 +60510,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
 
   /* Compilers may complain that mem1.u.i is potentially uninitialized.
   ** We could initialize it, as shown here, to silence those complaints.
-  ** But in fact, mem1.u.i will never actually be used initialized, and doing 
+  ** But in fact, mem1.u.i will never actually be used uninitialized, and doing 
   ** the unnecessary initialization has a measurable negative performance
   ** impact, since this routine is a very high runner.  And so, we choose
   ** to ignore the compiler warnings and leave this variable uninitialized.
@@ -60301,7 +60892,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
     Vdbe *v = (Vdbe*)pStmt;
     sqlite3_mutex_enter(v->db->mutex);
     rc = sqlite3VdbeReset(v);
-    sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0);
+    sqlite3VdbeRewind(v);
     assert( (rc & (v->db->errMask))==rc );
     rc = sqlite3ApiExit(v->db, rc);
     sqlite3_mutex_leave(v->db->mutex);
@@ -60658,6 +61249,14 @@ end_of_step:
   return (rc&db->errMask);
 }
 
+/*
+** The maximum number of times that a statement will try to reparse
+** itself before giving up and returning SQLITE_SCHEMA.
+*/
+#ifndef SQLITE_MAX_SCHEMA_RETRY
+# define SQLITE_MAX_SCHEMA_RETRY 5
+#endif
+
 /*
 ** This is the top-level implementation of sqlite3_step().  Call
 ** sqlite3Step() to do most of the work.  If a schema error occurs,
@@ -60676,7 +61275,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
   db = v->db;
   sqlite3_mutex_enter(db->mutex);
   while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
-         && cnt++ < 5
+         && cnt++ < SQLITE_MAX_SCHEMA_RETRY
          && (rc2 = rc = sqlite3Reprepare(v))==SQLITE_OK ){
     sqlite3_reset(pStmt);
     v->expired = 0;
@@ -61366,32 +61965,6 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
   return p ? p->nVar : 0;
 }
 
-/*
-** Create a mapping from variable numbers to variable names
-** in the Vdbe.azVar[] array, if such a mapping does not already
-** exist.
-*/
-static void createVarMap(Vdbe *p){
-  if( !p->okVar ){
-    int j;
-    Op *pOp;
-    sqlite3_mutex_enter(p->db->mutex);
-    /* The race condition here is harmless.  If two threads call this
-    ** routine on the same Vdbe at the same time, they both might end
-    ** up initializing the Vdbe.azVar[] array.  That is a little extra
-    ** work but it results in the same answer.
-    */
-    for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
-      if( pOp->opcode==OP_Variable ){
-        assert( pOp->p1>0 && pOp->p1<=p->nVar );
-        p->azVar[pOp->p1-1] = pOp->p4.z;
-      }
-    }
-    p->okVar = 1;
-    sqlite3_mutex_leave(p->db->mutex);
-  }
-}
-
 /*
 ** Return the name of a wildcard parameter.  Return NULL if the index
 ** is out of range or if the wildcard is unnamed.
@@ -61400,10 +61973,9 @@ static void createVarMap(Vdbe *p){
 */
 SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
   Vdbe *p = (Vdbe*)pStmt;
-  if( p==0 || i<1 || i>p->nVar ){
+  if( p==0 || i<1 || i>p->nzVar ){
     return 0;
   }
-  createVarMap(p);
   return p->azVar[i-1];
 }
 
@@ -61417,9 +61989,8 @@ SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nNa
   if( p==0 ){
     return 0;
   }
-  createVarMap(p); 
   if( zName ){
-    for(i=0; i<p->nVar; i++){
+    for(i=0; i<p->nzVar; i++){
       const char *z = p->azVar[i];
       if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
         return i+1;
@@ -62334,6 +62905,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
   Mem *pOut = 0;             /* Output operand */
   int iCompare = 0;          /* Result of last OP_Compare operation */
   int *aPermute = 0;         /* Permutation of columns for OP_Compare */
+  i64 lastRowid = db->lastRowid;  /* Saved value of the last insert ROWID */
 #ifdef VDBE_PROFILE
   u64 start;                 /* CPU clock count at start of opcode */
   int origPc;                /* Program counter at start of opcode */
@@ -62742,6 +63314,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
     } cm;
     struct OP_Trace_stack_vars {
       char *zTrace;
+      char *z;
     } cn;
   } u;
   /* End automatically generated code
@@ -62975,7 +63548,7 @@ case OP_Yield: {            /* in1 */
 
 /* Opcode:  HaltIfNull  P1 P2 P3 P4 *
 **
-** Check the value in register P3.  If is is NULL then Halt using
+** Check the value in register P3.  If it is NULL then Halt using
 ** parameter P1, P2, and P4 as if this were a Halt instruction.  If the
 ** value in register P3 is not NULL, then this routine is a no-op.
 */
@@ -63012,6 +63585,7 @@ case OP_Halt: {
     p->nFrame--;
     sqlite3VdbeSetChanges(db, p->nChange);
     pc = sqlite3VdbeFrameRestore(pFrame);
+    lastRowid = db->lastRowid;
     if( pOp->p2==OE_Ignore ){
       /* Instruction pc is the OP_Program that invoked the sub-program 
       ** currently being halted. If the p2 instruction of this OP_Halt
@@ -63167,6 +63741,7 @@ case OP_Variable: {            /* out2-prerelease */
 #endif /* local variables moved into u.ab */
 
   assert( pOp->p1>0 && pOp->p1<=p->nVar );
+  assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
   u.ab.pVar = &p->aVar[pOp->p1 - 1];
   if( sqlite3VdbeMemTooBig(u.ab.pVar) ){
     goto too_big;
@@ -63584,16 +64159,9 @@ case OP_Function: {
     assert( pOp[-1].opcode==OP_CollSeq );
     u.ag.ctx.pColl = pOp[-1].p4.pColl;
   }
+  db->lastRowid = lastRowid;
   (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */
-  if( db->mallocFailed ){
-    /* Even though a malloc() has failed, the implementation of the
-    ** user function may have called an sqlite3_result_XXX() function
-    ** to return a value. The following call releases any resources
-    ** associated with such a value.
-    */
-    sqlite3VdbeMemRelease(&u.ag.ctx.s);
-    goto no_mem;
-  }
+  lastRowid = db->lastRowid;
 
   /* If any auxiliary data functions have been called by this user function,
   ** immediately call the destructor for any non-static values.
@@ -63604,6 +64172,16 @@ case OP_Function: {
     pOp->p4type = P4_VDBEFUNC;
   }
 
+  if( db->mallocFailed ){
+    /* Even though a malloc() has failed, the implementation of the
+    ** user function may have called an sqlite3_result_XXX() function
+    ** to return a value. The following call releases any resources
+    ** associated with such a value.
+    */
+    sqlite3VdbeMemRelease(&u.ag.ctx.s);
+    goto no_mem;
+  }
+
   /* If the function returned an error, throw an exception */
   if( u.ag.ctx.isError ){
     sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.ag.ctx.s));
@@ -63907,7 +64485,7 @@ case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
 ** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
 ** true or false and is never NULL.  If both operands are NULL then the result
 ** of comparison is false.  If either operand is NULL then the result is true.
-** If neither operand is NULL the the result is the same as it would be if
+** If neither operand is NULL the result is the same as it would be if
 ** the SQLITE_NULLEQ flag were omitted from P5.
 */
 /* Opcode: Eq P1 P2 P3 P4 P5
@@ -63919,7 +64497,7 @@ case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
 ** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
 ** true or false and is never NULL.  If both operands are NULL then the result
 ** of comparison is true.  If either operand is NULL then the result is false.
-** If neither operand is NULL the the result is the same as it would be if
+** If neither operand is NULL the result is the same as it would be if
 ** the SQLITE_NULLEQ flag were omitted from P5.
 */
 /* Opcode: Le P1 P2 P3 P4 P5
@@ -63957,7 +64535,7 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
   pIn3 = &aMem[pOp->p3];
   u.ai.flags1 = pIn1->flags;
   u.ai.flags3 = pIn3->flags;
-  if( (pIn1->flags | pIn3->flags)&MEM_Null ){
+  if( (u.ai.flags1 | u.ai.flags3)&MEM_Null ){
     /* One or both operands are NULL */
     if( pOp->p5 & SQLITE_NULLEQ ){
       /* If SQLITE_NULLEQ is set (which will only happen if the operator is
@@ -63965,7 +64543,7 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
       ** or not both operands are null.
       */
       assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
-      u.ai.res = (pIn1->flags & pIn3->flags & MEM_Null)==0;
+      u.ai.res = (u.ai.flags1 & u.ai.flags3 & MEM_Null)==0;
     }else{
       /* SQLITE_NULLEQ is clear and at least one operand is NULL,
       ** then the result is always NULL.
@@ -64204,13 +64782,13 @@ case OP_BitNot: {             /* same as TK_BITNOT, in1, out2 */
 
 /* Opcode: If P1 P2 P3 * *
 **
-** Jump to P2 if the value in register P1 is true.  The value is
+** Jump to P2 if the value in register P1 is true.  The value
 ** is considered true if it is numeric and non-zero.  If the value
 ** in P1 is NULL then take the jump if P3 is true.
 */
 /* Opcode: IfNot P1 P2 P3 * *
 **
-** Jump to P2 if the value in register P1 is False.  The value is
+** Jump to P2 if the value in register P1 is False.  The value
 ** is considered true if it has a numeric value of zero.  If the value
 ** in P1 is NULL then take the jump if P3 is true.
 */
@@ -64791,6 +65369,17 @@ case OP_Savepoint: {
     }else{
       u.aq.nName = sqlite3Strlen30(u.aq.zName);
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+      /* This call is Ok even if this savepoint is actually a transaction
+      ** savepoint (and therefore should not prompt xSavepoint()) callbacks.
+      ** If this is a transaction savepoint being opened, it is guaranteed
+      ** that the db->aVTrans[] array is empty.  */
+      assert( db->autoCommit==0 || db->nVTrans==0 );
+      rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN,
+                                db->nStatement+db->nSavepoint);
+      if( rc!=SQLITE_OK ) goto abort_due_to_error;
+#endif
+
       /* Create a new savepoint structure. */
       u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1);
       if( u.aq.pNew ){
@@ -64897,6 +65486,11 @@ case OP_Savepoint: {
       }else{
         db->nDeferredCons = u.aq.pSavepoint->nDeferredCons;
       }
+
+      if( !isTransaction ){
+        rc = sqlite3VtabSavepoint(db, u.aq.p1, u.aq.iSavepoint);
+        if( rc!=SQLITE_OK ) goto abort_due_to_error;
+      }
     }
   }
 
@@ -65036,7 +65630,11 @@ case OP_Transaction: {
         db->nStatement++;
         p->iStatement = db->nSavepoint + db->nStatement;
       }
-      rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement);
+
+      rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement-1);
+      if( rc==SQLITE_OK ){
+        rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement);
+      }
 
       /* Store the current value of the database handles deferred constraint
       ** counter. If the statement transaction needs to be rolled back,
@@ -65357,7 +65955,7 @@ case OP_OpenEphemeral: {
   u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
   if( u.ax.pCx==0 ) goto no_mem;
   u.ax.pCx->nullRow = 1;
-  rc = sqlite3BtreeOpen(0, db, &u.ax.pCx->pBt,
+  rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ax.pCx->pBt,
                         BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
   if( rc==SQLITE_OK ){
     rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1);
@@ -65844,7 +66442,7 @@ case OP_IsUnique: {        /* jump, in3 */
 
 /* Opcode: NotExists P1 P2 P3 * *
 **
-** Use the content of register P3 as a integer key.  If a record 
+** Use the content of register P3 as an integer key.  If a record 
 ** with that key does not exist in table of P1, then jump to P2. 
 ** If the record does exist, then fall through.  The cursor is left 
 ** pointing to the record if it exists.
@@ -65922,7 +66520,7 @@ case OP_Sequence: {           /* out2-prerelease */
 ** If P3>0 then P3 is a register in the root frame of this VDBE that holds 
 ** the largest previously generated record number. No new record numbers are
 ** allowed to be less than this value. When this value reaches its maximum, 
-** a SQLITE_FULL error is generated. The P3 register is updated with the '
+** an SQLITE_FULL error is generated. The P3 register is updated with the '
 ** generated record number. This P3 mechanism is used to help implement the
 ** AUTOINCREMENT feature.
 */
@@ -66031,7 +66629,7 @@ case OP_NewRowid: {           /* out2-prerelease */
       assert( pOp->p3==0 );  /* We cannot be in random rowid mode if this is
                              ** an AUTOINCREMENT table. */
       /* on the first attempt, simply do one more than previous */
-      u.be.v = db->lastRowid;
+      u.be.v = lastRowid;
       u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */
       u.be.v++; /* ensure non-zero */
       u.be.cnt = 0;
@@ -66143,7 +66741,7 @@ case OP_InsertInt: {
   }
 
   if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
-  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = u.bf.iKey;
+  if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bf.iKey;
   if( u.bf.pData->flags & MEM_Null ){
     u.bf.pData->z = 0;
     u.bf.pData->n = 0;
@@ -66564,7 +67162,7 @@ case OP_Next: {        /* jump */
 
 /* Opcode: IdxInsert P1 P2 P3 * P5
 **
-** Register P2 holds a SQL index key made using the
+** Register P2 holds an SQL index key made using the
 ** MakeRecord instructions.  This opcode writes that key
 ** into the index P1.  Data for the entry is nil.
 **
@@ -67269,7 +67867,7 @@ case OP_Program: {        /* jump */
 
   p->nFrame++;
   u.by.pFrame->pParent = p->pFrame;
-  u.by.pFrame->lastRowid = db->lastRowid;
+  u.by.pFrame->lastRowid = lastRowid;
   u.by.pFrame->nChange = p->nChange;
   p->nChange = 0;
   p->pFrame = u.by.pFrame;
@@ -68080,11 +68678,15 @@ case OP_VUpdate: {
   Mem *pX;
 #endif /* local variables moved into u.cm */
 
+  assert( pOp->p2==1        || pOp->p5==OE_Fail   || pOp->p5==OE_Rollback
+       || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
+  );
   u.cm.pVtab = pOp->p4.pVtab->pVtab;
   u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule;
   u.cm.nArg = pOp->p2;
   assert( pOp->p4type==P4_VTAB );
   if( ALWAYS(u.cm.pModule->xUpdate) ){
+    u8 vtabOnConflict = db->vtabOnConflict;
     u.cm.apArg = p->apArg;
     u.cm.pX = &aMem[pOp->p3];
     for(u.cm.i=0; u.cm.i<u.cm.nArg; u.cm.i++){
@@ -68094,13 +68696,23 @@ case OP_VUpdate: {
       u.cm.apArg[u.cm.i] = u.cm.pX;
       u.cm.pX++;
     }
+    db->vtabOnConflict = pOp->p5;
     rc = u.cm.pModule->xUpdate(u.cm.pVtab, u.cm.nArg, u.cm.apArg, &u.cm.rowid);
+    db->vtabOnConflict = vtabOnConflict;
     importVtabErrMsg(p, u.cm.pVtab);
     if( rc==SQLITE_OK && pOp->p1 ){
       assert( u.cm.nArg>1 && u.cm.apArg[0] && (u.cm.apArg[0]->flags&MEM_Null) );
-      db->lastRowid = u.cm.rowid;
+      db->lastRowid = lastRowid = u.cm.rowid;
+    }
+    if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
+      if( pOp->p5==OE_Ignore ){
+        rc = SQLITE_OK;
+      }else{
+        p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5);
+      }
+    }else{
+      p->nChange++;
     }
-    p->nChange++;
   }
   break;
 }
@@ -68152,21 +68764,21 @@ case OP_MaxPgcnt: {            /* out2-prerelease */
 case OP_Trace: {
 #if 0  /* local variables moved into u.cn */
   char *zTrace;
+  char *z;
 #endif /* local variables moved into u.cn */
 
-  u.cn.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
-  if( u.cn.zTrace ){
-    if( db->xTrace ){
-      char *z = sqlite3VdbeExpandSql(p, u.cn.zTrace);
-      db->xTrace(db->pTraceArg, z);
-      sqlite3DbFree(db, z);
-    }
+  if( db->xTrace && (u.cn.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0 ){
+    u.cn.z = sqlite3VdbeExpandSql(p, u.cn.zTrace);
+    db->xTrace(db->pTraceArg, u.cn.z);
+    sqlite3DbFree(db, u.cn.z);
+  }
 #ifdef SQLITE_DEBUG
-    if( (db->flags & SQLITE_SqlTrace)!=0 ){
-      sqlite3DebugPrintf("SQL-trace: %s\n", u.cn.zTrace);
-    }
-#endif /* SQLITE_DEBUG */
+  if( (db->flags & SQLITE_SqlTrace)!=0
+   && (u.cn.zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
+  ){
+    sqlite3DebugPrintf("SQL-trace: %s\n", u.cn.zTrace);
   }
+#endif /* SQLITE_DEBUG */
   break;
 }
 #endif
@@ -68250,6 +68862,7 @@ vdbe_error_halt:
   ** release the mutexes on btrees that were acquired at the
   ** top. */
 vdbe_return:
+  db->lastRowid = lastRowid;
   sqlite3VdbeLeave(p);
   return rc;
 
@@ -68590,7 +69203,10 @@ SQLITE_API int sqlite3_blob_open(
       sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
       sqlite3VdbeChangeP2(v, 7, pTab->nCol);
       if( !db->mallocFailed ){
-        sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0);
+        pParse->nVar = 1;
+        pParse->nMem = 1;
+        pParse->nTab = 1;
+        sqlite3VdbeMakeReady(v, pParse);
       }
     }
    
@@ -71157,53 +71773,53 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
     /* Wildcard of the form "?".  Assign the next variable number */
     assert( z[0]=='?' );
     pExpr->iColumn = (ynVar)(++pParse->nVar);
-  }else if( z[0]=='?' ){
-    /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
-    ** use it as the variable number */
-    i64 i;
-    int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
-    pExpr->iColumn = (ynVar)i;
-    testcase( i==0 );
-    testcase( i==1 );
-    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
-    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
-    if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
-      sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
-          db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
-    }
-    if( i>pParse->nVar ){
-      pParse->nVar = (int)i;
-    }
   }else{
-    /* Wildcards like ":aaa", "$aaa" or "@aaa".  Reuse the same variable
-    ** number as the prior appearance of the same name, or if the name
-    ** has never appeared before, reuse the same variable number
-    */
-    int i;
-    u32 n;
-    n = sqlite3Strlen30(z);
-    for(i=0; i<pParse->nVarExpr; i++){
-      Expr *pE = pParse->apVarExpr[i];
-      assert( pE!=0 );
-      if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){
-        pExpr->iColumn = pE->iColumn;
-        break;
+    ynVar x = 0;
+    u32 n = sqlite3Strlen30(z);
+    if( z[0]=='?' ){
+      /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
+      ** use it as the variable number */
+      i64 i;
+      int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
+      pExpr->iColumn = x = (ynVar)i;
+      testcase( i==0 );
+      testcase( i==1 );
+      testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
+      testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
+      if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
+        sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
+            db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
+        x = 0;
+      }
+      if( i>pParse->nVar ){
+        pParse->nVar = (int)i;
       }
+    }else{
+      /* Wildcards like ":aaa", "$aaa" or "@aaa".  Reuse the same variable
+      ** number as the prior appearance of the same name, or if the name
+      ** has never appeared before, reuse the same variable number
+      */
+      ynVar i;
+      for(i=0; i<pParse->nzVar; i++){
+        if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
+          pExpr->iColumn = x = (ynVar)i+1;
+          break;
+        }
+      }
+      if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
     }
-    if( i>=pParse->nVarExpr ){
-      pExpr->iColumn = (ynVar)(++pParse->nVar);
-      if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
-        pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
-        pParse->apVarExpr =
-            sqlite3DbReallocOrFree(
-              db,
-              pParse->apVarExpr,
-              pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0])
-            );
+    if( x>0 ){
+      if( x>pParse->nzVar ){
+        char **a;
+        a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
+        if( a==0 ) return;  /* Error reported through db->mallocFailed */
+        pParse->azVar = a;
+        memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
+        pParse->nzVar = x;
       }
-      if( !db->mallocFailed ){
-        assert( pParse->apVarExpr!=0 );
-        pParse->apVarExpr[pParse->nVarExpr++] = pExpr;
+      if( z[0]!='?' || pParse->azVar[x-1]==0 ){
+        sqlite3DbFree(db, pParse->azVar[x-1]);
+        pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
       }
     }
   } 
@@ -72947,7 +73563,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
       assert( pExpr->u.zToken[0]!=0 );
       sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
       if( pExpr->u.zToken[1]!=0 ){
-        sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, P4_TRANSIENT);
+        assert( pExpr->u.zToken[0]=='?' 
+             || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 );
+        sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC);
       }
       break;
     }
@@ -74717,14 +75335,14 @@ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
   /* Reload the table, index and permanent trigger schemas. */
   zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
   if( !zWhere ) return;
-  sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
+  sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
 
 #ifndef SQLITE_OMIT_TRIGGER
   /* Now, if the table is not stored in the temp database, reload any temp 
   ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. 
   */
   if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
-    sqlite3VdbeAddOp4(v, OP_ParseSchema, 1, 0, 0, zWhere, P4_DYNAMIC);
+    sqlite3VdbeAddParseSchemaOp(v, 1, zWhere);
   }
 #endif
 }
@@ -75978,8 +76596,12 @@ static void attachFunc(
   sqlite3 *db = sqlite3_context_db_handle(context);
   const char *zName;
   const char *zFile;
+  char *zPath = 0;
+  char *zErr = 0;
+  unsigned int flags;
   Db *aNew;
   char *zErrDyn = 0;
+  sqlite3_vfs *pVfs;
 
   UNUSED_PARAMETER(NotUsed);
 
@@ -76032,8 +76654,18 @@ static void attachFunc(
   ** it to obtain the database schema. At this point the schema may
   ** or may not be initialised.
   */
-  rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0,
-                        db->openFlags | SQLITE_OPEN_MAIN_DB);
+  flags = db->openFlags;
+  rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
+  if( rc!=SQLITE_OK ){
+    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+    sqlite3_result_error(context, zErr, -1);
+    sqlite3_free(zErr);
+    return;
+  }
+  assert( pVfs );
+  flags |= SQLITE_OPEN_MAIN_DB;
+  rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
+  sqlite3_free( zPath );
   db->nDb++;
   if( rc==SQLITE_CONSTRAINT ){
     rc = SQLITE_ERROR;
@@ -76904,9 +77536,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
     /* A minimum of one cursor is required if autoincrement is used
     *  See ticket [a696379c1f08866] */
     if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
-    sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
-                         pParse->nTab, pParse->nMaxArg, pParse->explain,
-                         pParse->isMultiWrite && pParse->mayAbort);
+    sqlite3VdbeMakeReady(v, pParse);
     pParse->rc = SQLITE_DONE;
     pParse->colNamesSet = 0;
   }else{
@@ -78325,8 +78955,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
 #endif
 
     /* Reparse everything to update our internal data structures */
-    sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
-        sqlite3MPrintf(db, "tbl_name='%q'",p->zName), P4_DYNAMIC);
+    sqlite3VdbeAddParseSchemaOp(v, iDb,
+               sqlite3MPrintf(db, "tbl_name='%q'", p->zName));
   }
 
 
@@ -79523,9 +80153,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
     if( pTblName ){
       sqlite3RefillIndex(pParse, pIndex, iMem);
       sqlite3ChangeCookie(pParse, iDb);
-      sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0,
-         sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 
-         P4_DYNAMIC);
+      sqlite3VdbeAddParseSchemaOp(v, iDb,
+         sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
       sqlite3VdbeAddOp1(v, OP_Expire, 0);
     }
   }
@@ -80147,7 +80776,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
           SQLITE_OPEN_DELETEONCLOSE |
           SQLITE_OPEN_TEMP_DB;
 
-    rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags);
+    rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags);
     if( rc!=SQLITE_OK ){
       sqlite3ErrorMsg(pParse, "unable to open a temporary database "
         "file for storing temporary tables");
@@ -81323,6 +81952,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
       const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
       sqlite3VtabMakeWritable(pParse, pTab);
       sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
+      sqlite3VdbeChangeP5(v, OE_Abort);
       sqlite3MayAbort(pParse);
     }else
 #endif
@@ -81557,8 +82187,14 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
     }
   }
   if( doMakeRec ){
+    const char *zAff;
+    if( pTab->pSelect || (pParse->db->flags & SQLITE_IdxRealAsInt)!=0 ){
+      zAff = 0;
+    }else{
+      zAff = sqlite3IndexAffinityStr(v, pIdx);
+    }
     sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
-    sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
+    sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
   }
   sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
   return regBase;
@@ -82070,10 +82706,10 @@ struct compareInfo {
 ** whereas only characters less than 0x80 do in ASCII.
 */
 #if defined(SQLITE_EBCDIC)
-# define sqlite3Utf8Read(A,C)    (*(A++))
-# define GlogUpperToLower(A)     A = sqlite3UpperToLower[A]
+# define sqlite3Utf8Read(A,C)  (*(A++))
+# define GlogUpperToLower(A)   A = sqlite3UpperToLower[A]
 #else
-# define GlogUpperToLower(A)     if( A<0x80 ){ A = sqlite3UpperToLower[A]; }
+# define GlogUpperToLower(A)   if( !((A)&~0x7f) ){ A = sqlite3UpperToLower[A]; }
 #endif
 
 static const struct compareInfo globInfo = { '*', '?', '[', 0 };
@@ -82116,9 +82752,9 @@ static int patternCompare(
   const u8 *zPattern,              /* The glob pattern */
   const u8 *zString,               /* The string to compare against the glob */
   const struct compareInfo *pInfo, /* Information about how to do the compare */
-  const int esc                    /* The escape character */
+  u32 esc                          /* The escape character */
 ){
-  int c, c2;
+  u32 c, c2;
   int invert;
   int seen;
   u8 matchOne = pInfo->matchOne;
@@ -82172,7 +82808,7 @@ static int patternCompare(
         return 0;
       }
     }else if( c==matchSet ){
-      int prior_c = 0;
+      u32 prior_c = 0;
       assert( esc==0 );    /* This only occurs for GLOB, not LIKE */
       seen = 0;
       invert = 0;
@@ -82248,7 +82884,7 @@ static void likeFunc(
   sqlite3_value **argv
 ){
   const unsigned char *zA, *zB;
-  int escape = 0;
+  u32 escape = 0;
   int nPat;
   sqlite3 *db = sqlite3_context_db_handle(context);
 
@@ -82338,6 +82974,21 @@ static void sourceidFunc(
   sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC);
 }
 
+/*
+** Implementation of the sqlite_log() function.  This is a wrapper around
+** sqlite3_log().  The return value is NULL.  The function exists purely for
+** its side-effects.
+*/
+static void errlogFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  UNUSED_PARAMETER(argc);
+  UNUSED_PARAMETER(context);
+  sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1]));
+}
+
 /*
 ** Implementation of the sqlite_compileoption_used() function.
 ** The result is an integer that identifies if the compiler option
@@ -83105,6 +83756,7 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
     FUNCTION(sqlite_version,     0, 0, 0, versionFunc      ),
     FUNCTION(sqlite_source_id,   0, 0, 0, sourceidFunc     ),
+    FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
 #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
     FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
     FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
@@ -83543,13 +84195,25 @@ static void fkLookupParent(
       /* If the parent table is the same as the child table, and we are about
       ** to increment the constraint-counter (i.e. this is an INSERT operation),
       ** then check if the row being inserted matches itself. If so, do not
-      ** increment the constraint-counter.  */
+      ** increment the constraint-counter. 
+      **
+      ** If any of the parent-key values are NULL, then the row cannot match 
+      ** itself. So set JUMPIFNULL to make sure we do the OP_Found if any
+      ** of the parent-key values are NULL (at this point it is known that
+      ** none of the child key values are).
+      */
       if( pTab==pFKey->pFrom && nIncr==1 ){
         int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1;
         for(i=0; i<nCol; i++){
           int iChild = aiCol[i]+1+regData;
           int iParent = pIdx->aiColumn[i]+1+regData;
+          assert( aiCol[i]!=pTab->iPKey );
+          if( pIdx->aiColumn[i]==pTab->iPKey ){
+            /* The parent key is a composite key that includes the IPK column */
+            iParent = regData;
+          }
           sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent);
+          sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
         }
         sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
       }
@@ -85317,6 +85981,7 @@ SQLITE_PRIVATE void sqlite3Insert(
       const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
       sqlite3VtabMakeWritable(pParse, pTab);
       sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
+      sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
       sqlite3MayAbort(pParse);
     }else
 #endif
@@ -86082,6 +86747,18 @@ static int xferOptimization(
     return 0;   /* Tables have different CHECK constraints.  Ticket #2252 */
   }
 #endif
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+  /* Disallow the transfer optimization if the destination table constains
+  ** any foreign key constraints.  This is more restrictive than necessary.
+  ** But the main beneficiary of the transfer optimization is the VACUUM 
+  ** command, and the VACUUM command disables foreign key constraints.  So
+  ** the extra complication to make this rule less restrictive is probably
+  ** not worth the effort.  Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
+  */
+  if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
+    return 0;
+  }
+#endif
 
   /* If we get this far, it means either:
   **
@@ -87414,10 +88091,6 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
 ** This file contains code used to implement the PRAGMA command.
 */
 
-/* Ignore this whole file if pragmas are disabled
-*/
-#if !defined(SQLITE_OMIT_PRAGMA)
-
 /*
 ** Interpret the given string as a safety level.  Return 0 for OFF,
 ** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
@@ -87450,10 +88123,16 @@ static u8 getSafetyLevel(const char *z){
 /*
 ** Interpret the given string as a boolean value.
 */
-static u8 getBoolean(const char *z){
+SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z){
   return getSafetyLevel(z)&1;
 }
 
+/* The sqlite3GetBoolean() function is used by other modules but the
+** remainder of this file is specific to PRAGMA processing.  So omit
+** the rest of the file if PRAGMAs are omitted from the build.
+*/
+#if !defined(SQLITE_OMIT_PRAGMA)
+
 /*
 ** Interpret the given string as a locking mode value.
 */
@@ -87620,7 +88299,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
             mask &= ~(SQLITE_ForeignKeys);
           }
 
-          if( getBoolean(zRight) ){
+          if( sqlite3GetBoolean(zRight) ){
             db->flags |= mask;
           }else{
             db->flags &= ~mask;
@@ -87834,7 +88513,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     int b = -1;
     assert( pBt!=0 );
     if( zRight ){
-      b = getBoolean(zRight);
+      b = sqlite3GetBoolean(zRight);
     }
     if( pId2->n==0 && b>=0 ){
       int ii;
@@ -88434,7 +89113,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
 #ifndef NDEBUG
   if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
     if( zRight ){
-      if( getBoolean(zRight) ){
+      if( sqlite3GetBoolean(zRight) ){
         sqlite3ParserTrace(stderr, "parser: ");
       }else{
         sqlite3ParserTrace(0, 0);
@@ -88448,7 +89127,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
     if( zRight ){
-      sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
+      sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
     }
   }else
 
@@ -94026,11 +94705,13 @@ SQLITE_PRIVATE int sqlite3Select(
         ** and pKeyInfo to the KeyInfo structure required to navigate the
         ** index.
         **
+        ** (2011-04-15) Do not do a full scan of an unordered index.
+        **
         ** In practice the KeyInfo structure will not be used. It is only 
         ** passed to keep OP_OpenRead happy.
         */
         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-          if( !pBest || pIdx->nColumn<pBest->nColumn ){
+          if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
             pBest = pIdx;
           }
         }
@@ -94752,9 +95433,8 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
        pTrig->table, z);
     sqlite3DbFree(db, z);
     sqlite3ChangeCookie(pParse, iDb);
-    sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
-        db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC
-    );
+    sqlite3VdbeAddParseSchemaOp(v, iDb,
+        sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
   }
 
   if( db->init.busy ){
@@ -95587,7 +96267,8 @@ static void updateVirtualTable(
   ExprList *pChanges,  /* The columns to change in the UPDATE statement */
   Expr *pRowidExpr,    /* Expression used to recompute the rowid */
   int *aXRef,          /* Mapping from columns of pTab to entries in pChanges */
-  Expr *pWhere         /* WHERE clause of the UPDATE statement */
+  Expr *pWhere,        /* WHERE clause of the UPDATE statement */
+  int onError          /* ON CONFLICT strategy */
 );
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
@@ -95807,7 +96488,7 @@ SQLITE_PRIVATE void sqlite3Update(
   }
   for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
     int reg;
-    if( chngRowid ){
+    if( hasFK || chngRowid ){
       reg = ++pParse->nMem;
     }else{
       reg = 0;
@@ -95831,7 +96512,7 @@ SQLITE_PRIVATE void sqlite3Update(
   /* Virtual tables must be handled separately */
   if( IsVirtual(pTab) ){
     updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
-                       pWhere);
+                       pWhere, onError);
     pWhere = 0;
     pTabList = 0;
     goto update_cleanup;
@@ -96161,7 +96842,8 @@ static void updateVirtualTable(
   ExprList *pChanges,  /* The columns to change in the UPDATE statement */
   Expr *pRowid,        /* Expression used to recompute the rowid */
   int *aXRef,          /* Mapping from columns of pTab to entries in pChanges */
-  Expr *pWhere         /* WHERE clause of the UPDATE statement */
+  Expr *pWhere,        /* WHERE clause of the UPDATE statement */
+  int onError          /* ON CONFLICT strategy */
 ){
   Vdbe *v = pParse->pVdbe;  /* Virtual machine under construction */
   ExprList *pEList = 0;     /* The result set of the SELECT statement */
@@ -96218,6 +96900,7 @@ static void updateVirtualTable(
   }
   sqlite3VtabMakeWritable(pParse, pTab);
   sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
+  sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
   sqlite3MayAbort(pParse);
   sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
   sqlite3VdbeJumpHere(v, addr);
@@ -96591,6 +97274,18 @@ end_of_vacuum:
 */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 
+/*
+** Before a virtual table xCreate() or xConnect() method is invoked, the
+** sqlite3.pVtabCtx member variable is set to point to an instance of
+** this struct allocated on the stack. It is used by the implementation of 
+** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
+** are invoked only from within xCreate and xConnect methods.
+*/
+struct VtabCtx {
+  Table *pTab;
+  VTable *pVTable;
+};
+
 /*
 ** The actual function that does the work of creating a new module.
 ** This function implements the sqlite3_create_module() and
@@ -96619,13 +97314,13 @@ static int createModule(
     pMod->xDestroy = xDestroy;
     pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod);
     if( pDel && pDel->xDestroy ){
+      sqlite3ResetInternalSchema(db, -1);
       pDel->xDestroy(pDel->pAux);
     }
     sqlite3DbFree(db, pDel);
     if( pDel==pMod ){
       db->mallocFailed = 1;
     }
-    sqlite3ResetInternalSchema(db, -1);
   }else if( xDestroy ){
     xDestroy(pAux);
   }
@@ -96948,7 +97643,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
 
     sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
     zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
-    sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
+    sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
     sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, 
                          pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
   }
@@ -97011,6 +97706,7 @@ static int vtabCallConstructor(
   int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
   char **pzErr
 ){
+  VtabCtx sCtx;
   VTable *pVTable;
   int rc;
   const char *const*azArg = (const char *const*)pTab->azModuleArg;
@@ -97030,12 +97726,14 @@ static int vtabCallConstructor(
   pVTable->db = db;
   pVTable->pMod = pMod;
 
-  assert( !db->pVTab );
-  assert( xConstruct );
-  db->pVTab = pTab;
-
   /* Invoke the virtual table constructor */
+  assert( &db->pVtabCtx );
+  assert( xConstruct );
+  sCtx.pTab = pTab;
+  sCtx.pVTable = pVTable;
+  db->pVtabCtx = &sCtx;
   rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+  db->pVtabCtx = 0;
   if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
 
   if( SQLITE_OK!=rc ){
@@ -97051,7 +97749,7 @@ static int vtabCallConstructor(
     ** the sqlite3_vtab object if successful.  */
     pVTable->pVtab->pModule = pMod->pModule;
     pVTable->nRef = 1;
-    if( db->pVTab ){
+    if( sCtx.pTab ){
       const char *zFormat = "vtable constructor did not declare schema: %s";
       *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
       sqlite3VtabUnlock(pVTable);
@@ -97099,7 +97797,6 @@ static int vtabCallConstructor(
   }
 
   sqlite3DbFree(db, zModuleName);
-  db->pVTab = 0;
   return rc;
 }
 
@@ -97140,11 +97837,11 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
 
   return rc;
 }
-
 /*
-** Add the virtual table pVTab to the array sqlite3.aVTrans[].
+** Grow the db->aVTrans[] array so that there is room for at least one
+** more v-table. Return SQLITE_NOMEM if a malloc fails, or SQLITE_OK otherwise.
 */
-static int addToVTrans(sqlite3 *db, VTable *pVTab){
+static int growVTrans(sqlite3 *db){
   const int ARRAY_INCR = 5;
 
   /* Grow the sqlite3.aVTrans array if required */
@@ -97159,10 +97856,17 @@ static int addToVTrans(sqlite3 *db, VTable *pVTab){
     db->aVTrans = aVTrans;
   }
 
+  return SQLITE_OK;
+}
+
+/*
+** Add the virtual table pVTab to the array sqlite3.aVTrans[]. Space should
+** have already been reserved using growVTrans().
+*/
+static void addToVTrans(sqlite3 *db, VTable *pVTab){
   /* Add pVtab to the end of sqlite3.aVTrans */
   db->aVTrans[db->nVTrans++] = pVTab;
   sqlite3VtabLock(pVTab);
-  return SQLITE_OK;
 }
 
 /*
@@ -97200,7 +97904,10 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
   /* Justification of ALWAYS():  The xConstructor method is required to
   ** create a valid sqlite3_vtab if it returns SQLITE_OK. */
   if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){
-      rc = addToVTrans(db, sqlite3GetVTable(db, pTab));
+    rc = growVTrans(db);
+    if( rc==SQLITE_OK ){
+      addToVTrans(db, sqlite3GetVTable(db, pTab));
+    }
   }
 
   return rc;
@@ -97219,8 +97926,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
   char *zErr = 0;
 
   sqlite3_mutex_enter(db->mutex);
-  pTab = db->pVTab;
-  if( !pTab ){
+  if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
     sqlite3Error(db, SQLITE_MISUSE, 0);
     sqlite3_mutex_leave(db->mutex);
     return SQLITE_MISUSE_BKPT;
@@ -97247,7 +97953,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
         pParse->pNewTable->nCol = 0;
         pParse->pNewTable->aCol = 0;
       }
-      db->pVTab = 0;
+      db->pVtabCtx->pTab = 0;
     }else{
       sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
       sqlite3DbFree(db, zErr);
@@ -97317,6 +98023,7 @@ static void callFinaliser(sqlite3 *db, int offset){
         x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset);
         if( x ) x(p);
       }
+      pVTab->iSavepoint = 0;
       sqlite3VtabUnlock(pVTab);
     }
     sqlite3DbFree(db, db->aVTrans);
@@ -97399,7 +98106,6 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
   if( pModule->xBegin ){
     int i;
 
-
     /* If pVtab is already in the aVTrans array, return early */
     for(i=0; i<db->nVTrans; i++){
       if( db->aVTrans[i]==pVTab ){
@@ -97407,10 +98113,62 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
       }
     }
 
-    /* Invoke the xBegin method */
-    rc = pModule->xBegin(pVTab->pVtab);
+    /* Invoke the xBegin method. If successful, add the vtab to the 
+    ** sqlite3.aVTrans[] array. */
+    rc = growVTrans(db);
     if( rc==SQLITE_OK ){
-      rc = addToVTrans(db, pVTab);
+      rc = pModule->xBegin(pVTab->pVtab);
+      if( rc==SQLITE_OK ){
+        addToVTrans(db, pVTab);
+      }
+    }
+  }
+  return rc;
+}
+
+/*
+** Invoke either the xSavepoint, xRollbackTo or xRelease method of all
+** virtual tables that currently have an open transaction. Pass iSavepoint
+** as the second argument to the virtual table method invoked.
+**
+** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is
+** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is 
+** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with
+** an open transaction is invoked.
+**
+** If any virtual table method returns an error code other than SQLITE_OK, 
+** processing is abandoned and the error returned to the caller of this
+** function immediately. If all calls to virtual table methods are successful,
+** SQLITE_OK is returned.
+*/
+SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
+  int rc = SQLITE_OK;
+
+  assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
+  assert( iSavepoint>=0 );
+  if( db->aVTrans ){
+    int i;
+    for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
+      VTable *pVTab = db->aVTrans[i];
+      const sqlite3_module *pMod = pVTab->pMod->pModule;
+      if( pMod->iVersion>=2 ){
+        int (*xMethod)(sqlite3_vtab *, int);
+        switch( op ){
+          case SAVEPOINT_BEGIN:
+            xMethod = pMod->xSavepoint;
+            pVTab->iSavepoint = iSavepoint+1;
+            break;
+          case SAVEPOINT_ROLLBACK:
+            xMethod = pMod->xRollbackTo;
+            break;
+          default:
+            xMethod = pMod->xRelease;
+            break;
+        }
+        if( xMethod && pVTab->iSavepoint>iSavepoint ){
+          rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
+        }
+      }
     }
   }
   return rc;
@@ -97514,6 +98272,57 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
   }
 }
 
+/*
+** Return the ON CONFLICT resolution mode in effect for the virtual
+** table update operation currently in progress.
+**
+** The results of this routine are undefined unless it is called from
+** within an xUpdate method.
+*/
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
+  static const unsigned char aMap[] = { 
+    SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE 
+  };
+  assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 );
+  assert( OE_Ignore==4 && OE_Replace==5 );
+  assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 );
+  return (int)aMap[db->vtabOnConflict-1];
+}
+
+/*
+** Call from within the xCreate() or xConnect() methods to provide 
+** the SQLite core with additional information about the behavior
+** of the virtual table being implemented.
+*/
+SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
+  va_list ap;
+  int rc = SQLITE_OK;
+
+  sqlite3_mutex_enter(db->mutex);
+
+  va_start(ap, op);
+  switch( op ){
+    case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
+      VtabCtx *p = db->pVtabCtx;
+      if( !p ){
+        rc = SQLITE_MISUSE_BKPT;
+      }else{
+        assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 );
+        p->pVTable->bConstraint = (u8)va_arg(ap, int);
+      }
+      break;
+    }
+    default:
+      rc = SQLITE_MISUSE_BKPT;
+      break;
+  }
+  va_end(ap);
+
+  if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0);
+  sqlite3_mutex_leave(db->mutex);
+  return rc;
+}
+
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
 /************** End of vtab.c ************************************************/
@@ -106561,13 +107370,12 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
       testcase( z[0]=='x' ); testcase( z[0]=='X' );
       if( z[1]=='\'' ){
         *tokenType = TK_BLOB;
-        for(i=2; (c=z[i])!=0 && c!='\''; i++){
-          if( !sqlite3Isxdigit(c) ){
-            *tokenType = TK_ILLEGAL;
-          }
+        for(i=2; sqlite3Isxdigit(z[i]); i++){}
+        if( z[i]!='\'' || i%2 ){
+          *tokenType = TK_ILLEGAL;
+          while( z[i] && z[i]!='\'' ){ i++; }
         }
-        if( i%2 || !c ) *tokenType = TK_ILLEGAL;
-        if( c ) i++;
+        if( z[i] ) i++;
         return i;
       }
       /* Otherwise fall through to the next case */
@@ -106620,9 +107428,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
   assert( pParse->pNewTable==0 );
   assert( pParse->pNewTrigger==0 );
   assert( pParse->nVar==0 );
-  assert( pParse->nVarExpr==0 );
-  assert( pParse->nVarExprAlloc==0 );
-  assert( pParse->apVarExpr==0 );
+  assert( pParse->nzVar==0 );
+  assert( pParse->azVar==0 );
   enableLookaside = db->lookaside.bEnabled;
   if( db->lookaside.pStart ) db->lookaside.bEnabled = 1;
   while( !db->mallocFailed && zSql[i]!=0 ){
@@ -106716,7 +107523,8 @@ abort_parse:
   }
 
   sqlite3DeleteTrigger(db, pParse->pNewTrigger);
-  sqlite3DbFree(db, pParse->apVarExpr);
+  for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
+  sqlite3DbFree(db, pParse->azVar);
   sqlite3DbFree(db, pParse->aAlias);
   while( pParse->pAinc ){
     AutoincInfo *p = pParse->pAinc;
@@ -107536,6 +108344,11 @@ SQLITE_API int sqlite3_config(int op, ...){
       break;
     }
 
+    case SQLITE_CONFIG_URI: {
+      sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+      break;
+    }
+
     default: {
       rc = SQLITE_ERROR;
       break;
@@ -108895,6 +109708,236 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
   return oldLimit;                     /* IMP: R-53341-35419 */
 }
 
+/*
+** This function is used to parse both URIs and non-URI filenames passed by the
+** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
+** URIs specified as part of ATTACH statements.
+**
+** The first argument to this function is the name of the VFS to use (or
+** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx"
+** query parameter. The second argument contains the URI (or non-URI filename)
+** itself. When this function is called the *pFlags variable should contain
+** the default flags to open the database handle with. The value stored in
+** *pFlags may be updated before returning if the URI filename contains 
+** "cache=xxx" or "mode=xxx" query parameters.
+**
+** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
+** the VFS that should be used to open the database file. *pzFile is set to
+** point to a buffer containing the name of the file to open. It is the 
+** responsibility of the caller to eventually call sqlite3_free() to release
+** this buffer.
+**
+** If an error occurs, then an SQLite error code is returned and *pzErrMsg
+** may be set to point to a buffer containing an English language error 
+** message. It is the responsibility of the caller to eventually release
+** this buffer by calling sqlite3_free().
+*/
+SQLITE_PRIVATE int sqlite3ParseUri(
+  const char *zDefaultVfs,        /* VFS to use if no "vfs=xxx" query option */
+  const char *zUri,               /* Nul-terminated URI to parse */
+  unsigned int *pFlags,           /* IN/OUT: SQLITE_OPEN_XXX flags */
+  sqlite3_vfs **ppVfs,            /* OUT: VFS to use */ 
+  char **pzFile,                  /* OUT: Filename component of URI */
+  char **pzErrMsg                 /* OUT: Error message (if rc!=SQLITE_OK) */
+){
+  int rc = SQLITE_OK;
+  unsigned int flags = *pFlags;
+  const char *zVfs = zDefaultVfs;
+  char *zFile;
+  char c;
+  int nUri = sqlite3Strlen30(zUri);
+
+  assert( *pzErrMsg==0 );
+
+  if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) 
+   && nUri>=5 && memcmp(zUri, "file:", 5)==0 
+  ){
+    char *zOpt;
+    int eState;                   /* Parser state when parsing URI */
+    int iIn;                      /* Input character index */
+    int iOut = 0;                 /* Output character index */
+    int nByte = nUri+2;           /* Bytes of space to allocate */
+
+    /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen 
+    ** method that there may be extra parameters following the file-name.  */
+    flags |= SQLITE_OPEN_URI;
+
+    for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
+    zFile = sqlite3_malloc(nByte);
+    if( !zFile ) return SQLITE_NOMEM;
+
+    /* Discard the scheme and authority segments of the URI. */
+    if( zUri[5]=='/' && zUri[6]=='/' ){
+      iIn = 7;
+      while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
+
+      if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
+        *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s", 
+            iIn-7, &zUri[7]);
+        rc = SQLITE_ERROR;
+        goto parse_uri_out;
+      }
+    }else{
+      iIn = 5;
+    }
+
+    /* Copy the filename and any query parameters into the zFile buffer. 
+    ** Decode %HH escape codes along the way. 
+    **
+    ** Within this loop, variable eState may be set to 0, 1 or 2, depending
+    ** on the parsing context. As follows:
+    **
+    **   0: Parsing file-name.
+    **   1: Parsing name section of a name=value query parameter.
+    **   2: Parsing value section of a name=value query parameter.
+    */
+    eState = 0;
+    while( (c = zUri[iIn])!=0 && c!='#' ){
+      iIn++;
+      if( c=='%' 
+       && sqlite3Isxdigit(zUri[iIn]) 
+       && sqlite3Isxdigit(zUri[iIn+1]) 
+      ){
+        int octet = (sqlite3HexToInt(zUri[iIn++]) << 4);
+        octet += sqlite3HexToInt(zUri[iIn++]);
+
+        assert( octet>=0 && octet<256 );
+        if( octet==0 ){
+          /* This branch is taken when "%00" appears within the URI. In this
+          ** case we ignore all text in the remainder of the path, name or
+          ** value currently being parsed. So ignore the current character
+          ** and skip to the next "?", "=" or "&", as appropriate. */
+          while( (c = zUri[iIn])!=0 && c!='#' 
+              && (eState!=0 || c!='?')
+              && (eState!=1 || (c!='=' && c!='&'))
+              && (eState!=2 || c!='&')
+          ){
+            iIn++;
+          }
+          continue;
+        }
+        c = octet;
+      }else if( eState==1 && (c=='&' || c=='=') ){
+        if( zFile[iOut-1]==0 ){
+          /* An empty option name. Ignore this option altogether. */
+          while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++;
+          continue;
+        }
+        if( c=='&' ){
+          zFile[iOut++] = '\0';
+        }else{
+          eState = 2;
+        }
+        c = 0;
+      }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){
+        c = 0;
+        eState = 1;
+      }
+      zFile[iOut++] = c;
+    }
+    if( eState==1 ) zFile[iOut++] = '\0';
+    zFile[iOut++] = '\0';
+    zFile[iOut++] = '\0';
+
+    /* Check if there were any options specified that should be interpreted 
+    ** here. Options that are interpreted here include "vfs" and those that
+    ** correspond to flags that may be passed to the sqlite3_open_v2()
+    ** method. */
+    zOpt = &zFile[sqlite3Strlen30(zFile)+1];
+    while( zOpt[0] ){
+      int nOpt = sqlite3Strlen30(zOpt);
+      char *zVal = &zOpt[nOpt+1];
+      int nVal = sqlite3Strlen30(zVal);
+
+      if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){
+        zVfs = zVal;
+      }else{
+        struct OpenMode {
+          const char *z;
+          int mode;
+        } *aMode = 0;
+        char *zModeType = 0;
+        int mask = 0;
+        int limit = 0;
+
+        if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){
+          static struct OpenMode aCacheMode[] = {
+            { "shared",  SQLITE_OPEN_SHAREDCACHE },
+            { "private", SQLITE_OPEN_PRIVATECACHE },
+            { 0, 0 }
+          };
+
+          mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE;
+          aMode = aCacheMode;
+          limit = mask;
+          zModeType = "cache";
+        }
+        if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){
+          static struct OpenMode aOpenMode[] = {
+            { "ro",  SQLITE_OPEN_READONLY },
+            { "rw",  SQLITE_OPEN_READWRITE }, 
+            { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
+            { 0, 0 }
+          };
+
+          mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
+          aMode = aOpenMode;
+          limit = mask & flags;
+          zModeType = "access";
+        }
+
+        if( aMode ){
+          int i;
+          int mode = 0;
+          for(i=0; aMode[i].z; i++){
+            const char *z = aMode[i].z;
+            if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){
+              mode = aMode[i].mode;
+              break;
+            }
+          }
+          if( mode==0 ){
+            *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal);
+            rc = SQLITE_ERROR;
+            goto parse_uri_out;
+          }
+          if( mode>limit ){
+            *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s",
+                                        zModeType, zVal);
+            rc = SQLITE_PERM;
+            goto parse_uri_out;
+          }
+          flags = (flags & ~mask) | mode;
+        }
+      }
+
+      zOpt = &zVal[nVal+1];
+    }
+
+  }else{
+    zFile = sqlite3_malloc(nUri+2);
+    if( !zFile ) return SQLITE_NOMEM;
+    memcpy(zFile, zUri, nUri);
+    zFile[nUri] = '\0';
+    zFile[nUri+1] = '\0';
+  }
+
+  *ppVfs = sqlite3_vfs_find(zVfs);
+  if( *ppVfs==0 ){
+    *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs);
+    rc = SQLITE_ERROR;
+  }
+ parse_uri_out:
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(zFile);
+    zFile = 0;
+  }
+  *pFlags = flags;
+  *pzFile = zFile;
+  return rc;
+}
+
+
 /*
 ** This routine does the work of opening a database on behalf of
 ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
@@ -108903,12 +109946,14 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
 static int openDatabase(
   const char *zFilename, /* Database filename UTF-8 encoded */
   sqlite3 **ppDb,        /* OUT: Returned database handle */
-  unsigned flags,        /* Operational flags */
+  unsigned int flags,    /* Operational flags */
   const char *zVfs       /* Name of the VFS to use */
 ){
-  sqlite3 *db;
-  int rc;
-  int isThreadsafe;
+  sqlite3 *db;                    /* Store allocated handle here */
+  int rc;                         /* Return code */
+  int isThreadsafe;               /* True for threadsafe connections */
+  char *zOpen = 0;                /* Filename argument to pass to BtreeOpen() */
+  char *zErrMsg = 0;              /* Error message from sqlite3ParseUri() */
 
   *ppDb = 0;
 #ifndef SQLITE_OMIT_AUTOINIT
@@ -108932,7 +109977,7 @@ static int openDatabase(
   testcase( (1<<(flags&7))==0x02 ); /* READONLY */
   testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
   testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
-  if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE;
+  if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT;
 
   if( sqlite3GlobalConfig.bCoreMutex==0 ){
     isThreadsafe = 0;
@@ -109013,13 +110058,6 @@ static int openDatabase(
   sqlite3HashInit(&db->aModule);
 #endif
 
-  db->pVfs = sqlite3_vfs_find(zVfs);
-  if( !db->pVfs ){
-    rc = SQLITE_ERROR;
-    sqlite3Error(db, rc, "no such vfs: %s", zVfs);
-    goto opendb_out;
-  }
-
   /* Add the default collation sequence BINARY. BINARY works for both UTF-8
   ** and UTF-16, so add a version for each to avoid any unnecessary
   ** conversions. The only error that can occur here is a malloc() failure.
@@ -109042,9 +110080,18 @@ static int openDatabase(
   createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0,
                   nocaseCollatingFunc, 0);
 
-  /* Open the backend database driver */
+  /* Parse the filename/URI argument. */
   db->openFlags = flags;
-  rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0,
+  rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
+  if( rc!=SQLITE_OK ){
+    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
+    sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
+    sqlite3_free(zErrMsg);
+    goto opendb_out;
+  }
+
+  /* Open the backend database driver */
+  rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
                         flags | SQLITE_OPEN_MAIN_DB);
   if( rc!=SQLITE_OK ){
     if( rc==SQLITE_IOERR_NOMEM ){
@@ -109137,6 +110184,7 @@ static int openDatabase(
   sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
 
 opendb_out:
+  sqlite3_free(zOpen);
   if( db ){
     assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
     sqlite3_mutex_leave(db->mutex);
@@ -109168,7 +110216,7 @@ SQLITE_API int sqlite3_open_v2(
   int flags,              /* Flags */
   const char *zVfs        /* Name of VFS module to use */
 ){
-  return openDatabase(filename, ppDb, flags, zVfs);
+  return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
 }
 
 #ifndef SQLITE_OMIT_UTF16
@@ -109773,12 +110821,45 @@ SQLITE_API int sqlite3_test_control(int op, ...){
       break;
     }
 
+    /*   sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
+    **
+    ** If parameter onoff is non-zero, configure the wrappers so that all
+    ** subsequent calls to localtime() and variants fail. If onoff is zero,
+    ** undo this setting.
+    */
+    case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
+      sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
+      break;
+    }
+
   }
   va_end(ap);
 #endif /* SQLITE_OMIT_BUILTIN_TEST */
   return rc;
 }
 
+/*
+** This is a utility routine, useful to VFS implementations, that checks
+** to see if a database file was a URI that contained a specific query 
+** parameter, and if so obtains the value of the query parameter.
+**
+** The zFilename argument is the filename pointer passed into the xOpen()
+** method of a VFS implementation.  The zParam argument is the name of the
+** query parameter we seek.  This routine returns the value of the zParam
+** parameter if it exists.  If the parameter does not exist, this routine
+** returns a NULL pointer.
+*/
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+  zFilename += sqlite3Strlen30(zFilename) + 1;
+  while( zFilename[0] ){
+    int x = strcmp(zFilename, zParam);
+    zFilename += sqlite3Strlen30(zFilename) + 1;
+    if( x==0 ) return zFilename;
+    zFilename += sqlite3Strlen30(zFilename) + 1;
+  }
+  return 0;
+}
+
 /************** End of main.c ************************************************/
 /************** Begin file notify.c ******************************************/
 /*
@@ -110408,12 +111489,6 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
 ** into a single segment.
 */
 
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-
-#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE)
-# define SQLITE_CORE 1
-#endif
-
 /************** Include fts3Int.h in the middle of fts3.c ********************/
 /************** Begin file fts3Int.h *****************************************/
 /*
@@ -110429,7 +111504,6 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
 ******************************************************************************
 **
 */
-
 #ifndef _FTSINT_H
 #define _FTSINT_H
 
@@ -110437,6 +111511,16 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
 # define NDEBUG 1
 #endif
 
+/*
+** FTS4 is really an extension for FTS3.  It is enabled using the
+** SQLITE_ENABLE_FTS3 macro.  But to avoid confusion we also all
+** the SQLITE_ENABLE_FTS4 macro to serve as an alisse for SQLITE_ENABLE_FTS3.
+*/
+#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
+# define SQLITE_ENABLE_FTS3
+#endif
+
+#ifdef SQLITE_ENABLE_FTS3
 /************** Include fts3_tokenizer.h in the middle of fts3Int.h **********/
 /************** Begin file fts3_tokenizer.h **********************************/
 /*
@@ -110735,12 +111819,35 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
 */
 #define SizeofArray(X) ((int)(sizeof(X)/sizeof(X[0])))
 
+
+#ifndef MIN
+# define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
 /*
 ** Maximum length of a varint encoded integer. The varint format is different
 ** from that used by SQLite, so the maximum length is 10, not 9.
 */
 #define FTS3_VARINT_MAX 10
 
+/*
+** FTS4 virtual tables may maintain multiple indexes - one index of all terms
+** in the document set and zero or more prefix indexes. All indexes are stored
+** as one or more b+-trees in the %_segments and %_segdir tables. 
+**
+** It is possible to determine which index a b+-tree belongs to based on the
+** value stored in the "%_segdir.level" column. Given this value L, the index
+** that the b+-tree belongs to is (L<<10). In other words, all b+-trees with
+** level values between 0 and 1023 (inclusive) belong to index 0, all levels
+** between 1024 and 2047 to index 1, and so on.
+**
+** It is considered impossible for an index to use more than 1024 levels. In 
+** theory though this may happen, but only after at least 
+** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables.
+*/
+#define FTS3_SEGDIR_MAXLEVEL      1024
+#define FTS3_SEGDIR_MAXLEVEL_STR "1024"
+
 /*
 ** The testcase() macro is only used by the amalgamation.  If undefined,
 ** make it a no-op.
@@ -110780,22 +111887,43 @@ typedef unsigned char u8;         /* 1-byte (or larger) unsigned integer */
 typedef short int i16;            /* 2-byte (or larger) signed integer */
 typedef unsigned int u32;         /* 4-byte unsigned integer */
 typedef sqlite3_uint64 u64;       /* 8-byte unsigned integer */
+
 /*
 ** Macro used to suppress compiler warnings for unused parameters.
 */
 #define UNUSED_PARAMETER(x) (void)(x)
+
+/*
+** Activate assert() only if SQLITE_TEST is enabled.
+*/
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
+# define NDEBUG 1
+#endif
+
+/*
+** The TESTONLY macro is used to enclose variable declarations or
+** other bits of code that are needed to support the arguments
+** within testcase() and assert() macros.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
+# define TESTONLY(X)  X
+#else
+# define TESTONLY(X)
 #endif
 
+#endif /* SQLITE_AMALGAMATION */
+
 typedef struct Fts3Table Fts3Table;
 typedef struct Fts3Cursor Fts3Cursor;
 typedef struct Fts3Expr Fts3Expr;
 typedef struct Fts3Phrase Fts3Phrase;
 typedef struct Fts3PhraseToken Fts3PhraseToken;
 
+typedef struct Fts3Doclist Fts3Doclist;
 typedef struct Fts3SegFilter Fts3SegFilter;
 typedef struct Fts3DeferredToken Fts3DeferredToken;
 typedef struct Fts3SegReader Fts3SegReader;
-typedef struct Fts3SegReaderCursor Fts3SegReaderCursor;
+typedef struct Fts3MultiSegReader Fts3MultiSegReader;
 
 /*
 ** A connection to a fulltext index is an instance of the following
@@ -110816,7 +111944,7 @@ struct Fts3Table {
   /* Precompiled statements used by the implementation. Each of these 
   ** statements is run and reset within a single virtual table API call. 
   */
-  sqlite3_stmt *aStmt[24];
+  sqlite3_stmt *aStmt[27];
 
   char *zReadExprlist;
   char *zWriteExprlist;
@@ -110824,21 +111952,43 @@ struct Fts3Table {
   int nNodeSize;                  /* Soft limit for node size */
   u8 bHasStat;                    /* True if %_stat table exists */
   u8 bHasDocsize;                 /* True if %_docsize table exists */
+  u8 bDescIdx;                    /* True if doclists are in reverse order */
   int nPgsz;                      /* Page size for host database */
   char *zSegmentsTbl;             /* Name of %_segments table */
   sqlite3_blob *pSegments;        /* Blob handle open on %_segments table */
 
-  /* The following hash table is used to buffer pending index updates during
+  /* TODO: Fix the first paragraph of this comment.
+  **
+  ** The following hash table is used to buffer pending index updates during
   ** transactions. Variable nPendingData estimates the memory size of the 
   ** pending data, including hash table overhead, but not malloc overhead. 
   ** When nPendingData exceeds nMaxPendingData, the buffer is flushed 
   ** automatically. Variable iPrevDocid is the docid of the most recently
   ** inserted record.
+  **
+  ** A single FTS4 table may have multiple full-text indexes. For each index
+  ** there is an entry in the aIndex[] array. Index 0 is an index of all the
+  ** terms that appear in the document set. Each subsequent index in aIndex[]
+  ** is an index of prefixes of a specific length.
+  */
+  int nIndex;                     /* Size of aIndex[] */
+  struct Fts3Index {
+    int nPrefix;                  /* Prefix length (0 for main terms index) */
+    Fts3Hash hPending;            /* Pending terms table for this index */
+  } *aIndex;
+  int nMaxPendingData;            /* Max pending data before flush to disk */
+  int nPendingData;               /* Current bytes of pending data */
+  sqlite_int64 iPrevDocid;        /* Docid of most recently inserted document */
+
+#if defined(SQLITE_DEBUG)
+  /* State variables used for validating that the transaction control
+  ** methods of the virtual table are called at appropriate times.  These
+  ** values do not contribution to the FTS computation; they are used for
+  ** verifying the SQLite core.
   */
-  int nMaxPendingData;
-  int nPendingData;
-  sqlite_int64 iPrevDocid;
-  Fts3Hash pendingTerms;
+  int inTransaction;     /* True after xBegin but before xCommit/xRollback */
+  int mxSavepoint;       /* Largest valid xSavepoint integer */
+#endif
 };
 
 /*
@@ -110859,8 +112009,10 @@ struct Fts3Cursor {
   char *pNextId;                  /* Pointer into the body of aDoclist */
   char *aDoclist;                 /* List of docids for full-text queries */
   int nDoclist;                   /* Size of buffer at aDoclist */
+  u8 bDesc;                       /* True to sort in descending order */
   int eEvalmode;                  /* An FTS3_EVAL_XX constant */
   int nRowAvg;                    /* Average size of database rows, in pages */
+  sqlite3_int64 nDoc;             /* Documents in table */
 
   int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
   u32 *aMatchinfo;                /* Information about most recent match */
@@ -110891,47 +112043,70 @@ struct Fts3Cursor {
 #define FTS3_DOCID_SEARCH    1    /* Lookup by rowid on %_content table */
 #define FTS3_FULLTEXT_SEARCH 2    /* Full-text index search */
 
+
+struct Fts3Doclist {
+  char *aAll;                    /* Array containing doclist (or NULL) */
+  int nAll;                      /* Size of a[] in bytes */
+  char *pNextDocid;              /* Pointer to next docid */
+
+  sqlite3_int64 iDocid;          /* Current docid (if pList!=0) */
+  int bFreeList;                 /* True if pList should be sqlite3_free()d */
+  char *pList;                   /* Pointer to position list following iDocid */
+  int nList;                     /* Length of position list */
+} doclist;
+
 /*
 ** A "phrase" is a sequence of one or more tokens that must match in
 ** sequence.  A single token is the base case and the most common case.
 ** For a sequence of tokens contained in double-quotes (i.e. "one two three")
 ** nToken will be the number of tokens in the string.
-**
-** The nDocMatch and nMatch variables contain data that may be used by the
-** matchinfo() function. They are populated when the full-text index is 
-** queried for hits on the phrase. If one or more tokens in the phrase
-** are deferred, the nDocMatch and nMatch variables are populated based
-** on the assumption that the 
 */
 struct Fts3PhraseToken {
   char *z;                        /* Text of the token */
   int n;                          /* Number of bytes in buffer z */
   int isPrefix;                   /* True if token ends with a "*" character */
-  int bFulltext;                  /* True if full-text index was used */
-  Fts3SegReaderCursor *pSegcsr;   /* Segment-reader for this token */
+
+  /* Variables above this point are populated when the expression is
+  ** parsed (by code in fts3_expr.c). Below this point the variables are
+  ** used when evaluating the expression. */
   Fts3DeferredToken *pDeferred;   /* Deferred token object for this token */
+  Fts3MultiSegReader *pSegcsr;    /* Segment-reader for this token */
 };
 
 struct Fts3Phrase {
-  /* Variables populated by fts3_expr.c when parsing a MATCH expression */
+  /* Cache of doclist for this phrase. */
+  Fts3Doclist doclist;
+  int bIncr;                 /* True if doclist is loaded incrementally */
+  int iDoclistToken;
+
+  /* Variables below this point are populated by fts3_expr.c when parsing 
+  ** a MATCH expression. Everything above is part of the evaluation phase. 
+  */
   int nToken;                /* Number of tokens in the phrase */
   int iColumn;               /* Index of column this phrase must match */
-  int isNot;                 /* Phrase prefixed by unary not (-) operator */
   Fts3PhraseToken aToken[1]; /* One entry for each token in the phrase */
 };
 
 /*
 ** A tree of these objects forms the RHS of a MATCH operator.
 **
-** If Fts3Expr.eType is either FTSQUERY_NEAR or FTSQUERY_PHRASE and isLoaded
-** is true, then aDoclist points to a malloced buffer, size nDoclist bytes, 
-** containing the results of the NEAR or phrase query in FTS3 doclist
-** format. As usual, the initial "Length" field found in doclists stored
-** on disk is omitted from this buffer.
+** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist 
+** points to a malloced buffer, size nDoclist bytes, containing the results 
+** of this phrase query in FTS3 doclist format. As usual, the initial 
+** "Length" field found in doclists stored on disk is omitted from this 
+** buffer.
+**
+** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global
+** matchinfo data. If it is not NULL, it points to an array of size nCol*3,
+** where nCol is the number of columns in the queried FTS table. The array
+** is populated as follows:
+**
+**   aMI[iCol*3 + 0] = Undefined
+**   aMI[iCol*3 + 1] = Number of occurrences
+**   aMI[iCol*3 + 2] = Number of rows containing at least one instance
 **
-** Variable pCurrent always points to the start of a docid field within
-** aDoclist. Since the doclist is usually scanned in docid order, this can
-** be used to accelerate seeking to the required docid within the doclist.
+** The aMI array is allocated using sqlite3_malloc(). It should be freed 
+** when the expression node is.
 */
 struct Fts3Expr {
   int eType;                 /* One of the FTSQUERY_XXX values defined below */
@@ -110941,12 +112116,13 @@ struct Fts3Expr {
   Fts3Expr *pRight;          /* Right operand */
   Fts3Phrase *pPhrase;       /* Valid if eType==FTSQUERY_PHRASE */
 
-  int isLoaded;              /* True if aDoclist/nDoclist are initialized. */
-  char *aDoclist;            /* Buffer containing doclist */
-  int nDoclist;              /* Size of aDoclist in bytes */
+  /* The following are used by the fts3_eval.c module. */
+  sqlite3_int64 iDocid;      /* Current docid */
+  u8 bEof;                   /* True this expression is at EOF already */
+  u8 bStart;                 /* True if iDocid is valid */
+  u8 bDeferred;              /* True if this expression is entirely deferred */
 
-  sqlite3_int64 iCurrent;
-  char *pCurrent;
+  u32 *aMI;
 };
 
 /*
@@ -110974,12 +112150,12 @@ SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *);
 SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *);
 SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
   sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
+SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
+  Fts3Table*,int,const char*,int,int,Fts3SegReader**);
 SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
-SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, sqlite3_stmt **);
+SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table*, int, int, sqlite3_stmt **);
 SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *);
-SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);
+SQLITE_PRIVATE int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*, int*);
 
 SQLITE_PRIVATE int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
 SQLITE_PRIVATE int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
@@ -110988,17 +112164,18 @@ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
 SQLITE_PRIVATE int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
 SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
 SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
-SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);
 SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *);
 
-#define FTS3_SEGCURSOR_PENDING -1
-#define FTS3_SEGCURSOR_ALL     -2
+/* Special values interpreted by sqlite3SegReaderCursor() */
+#define FTS3_SEGCURSOR_PENDING        -1
+#define FTS3_SEGCURSOR_ALL            -2
+
+SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Fts3SegFilter*);
+SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
+SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *);
 
-SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3SegReaderCursor*, Fts3SegFilter*);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3SegReaderCursor *);
-SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3SegReaderCursor *);
 SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
-    Fts3Table *, int, const char *, int, int, int, Fts3SegReaderCursor *);
+    Fts3Table *, int, int, const char *, int, int, int, Fts3MultiSegReader *);
 
 /* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
 #define FTS3_SEGMENT_REQUIRE_POS   0x00000001
@@ -111015,7 +112192,7 @@ struct Fts3SegFilter {
   int flags;
 };
 
-struct Fts3SegReaderCursor {
+struct Fts3MultiSegReader {
   /* Used internally by sqlite3Fts3SegReaderXXX() calls */
   Fts3SegReader **apSegment;      /* Array of Fts3SegReader objects */
   int nSegment;                   /* Size of apSegment array */
@@ -111024,8 +112201,12 @@ struct Fts3SegReaderCursor {
   char *aBuffer;                  /* Buffer to merge doclists in */
   int nBuffer;                    /* Allocated size of aBuffer[] in bytes */
 
-  /* Cost of running this iterator. Used by fts3.c only. */
-  int nCost;
+  int iColFilter;                 /* If >=0, filter for this column */
+  int bRestart;
+
+  /* Used by fts3.c only. */
+  int nCost;                      /* Cost of running iterator */
+  int bLookup;                    /* True if a lookup of a single entry. */
 
   /* Output values. Valid only after Fts3SegReaderStep() returns SQLITE_ROW. */
   char *zTerm;                    /* Pointer to term buffer */
@@ -111040,11 +112221,9 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
 SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
 SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
 SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
+SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
 
-SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int);
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *);
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *);
-SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int);
+SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
 
 /* fts3_tokenizer.c */
 SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
@@ -111068,15 +112247,45 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
 SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
 #ifdef SQLITE_TEST
 SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
+SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
 #endif
 
 /* fts3_aux.c */
 SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db);
 
+SQLITE_PRIVATE int sqlite3Fts3TermSegReaderCursor(
+  Fts3Cursor *pCsr,               /* Virtual table cursor handle */
+  const char *zTerm,              /* Term to query for */
+  int nTerm,                      /* Size of zTerm in bytes */
+  int isPrefix,                   /* True for a prefix search */
+  Fts3MultiSegReader **ppSegcsr   /* OUT: Allocated seg-reader cursor */
+);
+
+SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *);
+
+SQLITE_PRIVATE int sqlite3Fts3EvalStart(Fts3Cursor *, Fts3Expr *, int);
+SQLITE_PRIVATE int sqlite3Fts3EvalNext(Fts3Cursor *pCsr);
+
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
+    Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
+    Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
+SQLITE_PRIVATE char *sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol); 
+SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
+
+SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *);
+
+#endif /* SQLITE_ENABLE_FTS3 */
 #endif /* _FTSINT_H */
 
 /************** End of fts3Int.h *********************************************/
 /************** Continuing where we left off in fts3.c ***********************/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+
+#if defined(SQLITE_ENABLE_FTS3) && !defined(SQLITE_CORE)
+# define SQLITE_CORE 1
+#endif
 
 
 #ifndef SQLITE_CORE 
@@ -111190,17 +112399,31 @@ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
 }
 
 /*
-** As long as *pp has not reached its end (pEnd), then do the same
-** as fts3GetDeltaVarint(): read a single varint and add it to *pVal.
-** But if we have reached the end of the varint, just set *pp=0 and
-** leave *pVal unchanged.
+** When this function is called, *pp points to the first byte following a
+** varint that is part of a doclist (or position-list, or any other list
+** of varints). This function moves *pp to point to the start of that varint,
+** and sets *pVal by the varint value.
+**
+** Argument pStart points to the first byte of the doclist that the
+** varint is part of.
 */
-static void fts3GetDeltaVarint2(char **pp, char *pEnd, sqlite3_int64 *pVal){
-  if( *pp>=pEnd ){
-    *pp = 0;
-  }else{
-    fts3GetDeltaVarint(pp, pVal);
-  }
+static void fts3GetReverseVarint(
+  char **pp, 
+  char *pStart, 
+  sqlite3_int64 *pVal
+){
+  sqlite3_int64 iVal;
+  char *p = *pp;
+
+  /* Pointer p now points at the first byte past the varint we are 
+  ** interested in. So, unless the doclist is corrupt, the 0x80 bit is
+  ** clear on character p[-1]. */
+  for(p = (*pp)-2; p>=pStart && *p&0x80; p--);
+  p++;
+  *pp = p;
+
+  sqlite3Fts3GetVarint(p, &iVal);
+  *pVal = iVal;
 }
 
 /*
@@ -111294,6 +112517,8 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
     char *zSql;                   /* SQL statement passed to declare_vtab() */
     char *zCols;                  /* List of user defined columns */
 
+    sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+
     /* Create a list of user columns for the virtual table */
     zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
     for(i=1; zCols && i<p->nColumn; i++){
@@ -111399,6 +112624,9 @@ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
         sqlite3_step(pStmt);
         p->nPgsz = sqlite3_column_int(pStmt, 0);
         rc = sqlite3_finalize(pStmt);
+      }else if( rc==SQLITE_AUTH ){
+        p->nPgsz = 1024;
+        rc = SQLITE_OK;
       }
     }
     assert( p->nPgsz>0 || rc!=SQLITE_OK );
@@ -111572,6 +112800,58 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
   return zRet;
 }
 
+static int fts3GobbleInt(const char **pp, int *pnOut){
+  const char *p = *pp;
+  int nInt = 0;
+  for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
+    nInt = nInt * 10 + (p[0] - '0');
+  }
+  if( p==*pp ) return SQLITE_ERROR;
+  *pnOut = nInt;
+  *pp = p;
+  return SQLITE_OK;
+}
+
+
+static int fts3PrefixParameter(
+  const char *zParam,             /* ABC in prefix=ABC parameter to parse */
+  int *pnIndex,                   /* OUT: size of *apIndex[] array */
+  struct Fts3Index **apIndex,     /* OUT: Array of indexes for this table */
+  struct Fts3Index **apFree       /* OUT: Free this with sqlite3_free() */
+){
+  struct Fts3Index *aIndex;
+  int nIndex = 1;
+
+  if( zParam && zParam[0] ){
+    const char *p;
+    nIndex++;
+    for(p=zParam; *p; p++){
+      if( *p==',' ) nIndex++;
+    }
+  }
+
+  aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
+  *apIndex = *apFree = aIndex;
+  *pnIndex = nIndex;
+  if( !aIndex ){
+    return SQLITE_NOMEM;
+  }
+
+  memset(aIndex, 0, sizeof(struct Fts3Index) * nIndex);
+  if( zParam ){
+    const char *p = zParam;
+    int i;
+    for(i=1; i<nIndex; i++){
+      int nPrefix;
+      if( fts3GobbleInt(&p, &nPrefix) ) return SQLITE_ERROR;
+      aIndex[i].nPrefix = nPrefix;
+      p++;
+    }
+  }
+
+  return SQLITE_OK;
+}
+
 /*
 ** This function is the implementation of both the xConnect and xCreate
 ** methods of the FTS3 virtual table.
@@ -111604,12 +112884,19 @@ static int fts3InitVtab(
   int nDb;                        /* Bytes required to hold database name */
   int nName;                      /* Bytes required to hold table name */
   int isFts4 = (argv[0][3]=='4'); /* True for FTS4, false for FTS3 */
-  int bNoDocsize = 0;             /* True to omit %_docsize table */
   const char **aCol;              /* Array of column names */
   sqlite3_tokenizer *pTokenizer = 0;        /* Tokenizer for this table */
 
-  char *zCompress = 0;
-  char *zUncompress = 0;
+  int nIndex;                     /* Size of aIndex[] array */
+  struct Fts3Index *aIndex;       /* Array of indexes for this table */
+  struct Fts3Index *aFree = 0;    /* Free this before returning */
+
+  /* The results of parsing supported FTS4 key=value options: */
+  int bNoDocsize = 0;             /* True to omit %_docsize table */
+  int bDescIdx = 0;               /* True to store descending indexes */
+  char *zPrefix = 0;              /* Prefix parameter value (or NULL) */
+  char *zCompress = 0;            /* compress=? parameter (or NULL) */
+  char *zUncompress = 0;          /* uncompress=? parameter (or NULL) */
 
   assert( strlen(argv[0])==4 );
   assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
@@ -111650,28 +112937,72 @@ static int fts3InitVtab(
 
     /* Check if it is an FTS4 special argument. */
     else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
+      struct Fts4Option {
+        const char *zOpt;
+        int nOpt;
+        char **pzVar;
+      } aFts4Opt[] = {
+        { "matchinfo",   9, 0 },            /* 0 -> MATCHINFO */
+        { "prefix",      6, 0 },            /* 1 -> PREFIX */
+        { "compress",    8, 0 },            /* 2 -> COMPRESS */
+        { "uncompress", 10, 0 },            /* 3 -> UNCOMPRESS */
+        { "order",       5, 0 }             /* 4 -> ORDER */
+      };
+
+      int iOpt;
       if( !zVal ){
         rc = SQLITE_NOMEM;
-        goto fts3_init_out;
-      }
-      if( nKey==9 && 0==sqlite3_strnicmp(z, "matchinfo", 9) ){
-        if( strlen(zVal)==4 && 0==sqlite3_strnicmp(zVal, "fts3", 4) ){
-          bNoDocsize = 1;
-        }else{
-          *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal);
+      }else{
+        for(iOpt=0; iOpt<SizeofArray(aFts4Opt); iOpt++){
+          struct Fts4Option *pOp = &aFts4Opt[iOpt];
+          if( nKey==pOp->nOpt && !sqlite3_strnicmp(z, pOp->zOpt, pOp->nOpt) ){
+            break;
+          }
+        }
+        if( iOpt==SizeofArray(aFts4Opt) ){
+          *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z);
           rc = SQLITE_ERROR;
+        }else{
+          switch( iOpt ){
+            case 0:               /* MATCHINFO */
+              if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
+                *pzErr = sqlite3_mprintf("unrecognized matchinfo: %s", zVal);
+                rc = SQLITE_ERROR;
+              }
+              bNoDocsize = 1;
+              break;
+
+            case 1:               /* PREFIX */
+              sqlite3_free(zPrefix);
+              zPrefix = zVal;
+              zVal = 0;
+              break;
+
+            case 2:               /* COMPRESS */
+              sqlite3_free(zCompress);
+              zCompress = zVal;
+              zVal = 0;
+              break;
+
+            case 3:               /* UNCOMPRESS */
+              sqlite3_free(zUncompress);
+              zUncompress = zVal;
+              zVal = 0;
+              break;
+
+            case 4:               /* ORDER */
+              if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3)) 
+               && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3)) 
+              ){
+                *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
+                rc = SQLITE_ERROR;
+              }
+              bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
+              break;
+          }
         }
-      }else if( nKey==8 && 0==sqlite3_strnicmp(z, "compress", 8) ){
-        zCompress = zVal;
-        zVal = 0;
-      }else if( nKey==10 && 0==sqlite3_strnicmp(z, "uncompress", 10) ){
-        zUncompress = zVal;
-        zVal = 0;
-      }else{
-        *pzErr = sqlite3_mprintf("unrecognized parameter: %s", z);
-        rc = SQLITE_ERROR;
+        sqlite3_free(zVal);
       }
-      sqlite3_free(zVal);
     }
 
     /* Otherwise, the argument is a column name. */
@@ -111695,10 +113026,17 @@ static int fts3InitVtab(
   }
   assert( pTokenizer );
 
+  rc = fts3PrefixParameter(zPrefix, &nIndex, &aIndex, &aFree);
+  if( rc==SQLITE_ERROR ){
+    assert( zPrefix );
+    *pzErr = sqlite3_mprintf("error parsing prefix parameter: %s", zPrefix);
+  }
+  if( rc!=SQLITE_OK ) goto fts3_init_out;
 
   /* Allocate and populate the Fts3Table structure. */
-  nByte = sizeof(Fts3Table) +              /* Fts3Table */
+  nByte = sizeof(Fts3Table) +                  /* Fts3Table */
           nCol * sizeof(char *) +              /* azColumn */
+          nIndex * sizeof(struct Fts3Index) +  /* aIndex */
           nName +                              /* zName */
           nDb +                                /* zDb */
           nString;                             /* Space for azColumn strings */
@@ -111713,14 +113051,22 @@ static int fts3InitVtab(
   p->nPendingData = 0;
   p->azColumn = (char **)&p[1];
   p->pTokenizer = pTokenizer;
-  p->nNodeSize = 1000;
   p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
   p->bHasDocsize = (isFts4 && bNoDocsize==0);
   p->bHasStat = isFts4;
-  fts3HashInit(&p->pendingTerms, FTS3_HASH_STRING, 1);
+  p->bDescIdx = bDescIdx;
+  TESTONLY( p->inTransaction = -1 );
+  TESTONLY( p->mxSavepoint = -1 );
+
+  p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
+  memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
+  p->nIndex = nIndex;
+  for(i=0; i<nIndex; i++){
+    fts3HashInit(&p->aIndex[i].hPending, FTS3_HASH_STRING, 1);
+  }
 
   /* Fill in the zName and zDb fields of the vtab structure. */
-  zCsr = (char *)&p->azColumn[nCol];
+  zCsr = (char *)&p->aIndex[nIndex];
   p->zName = zCsr;
   memcpy(zCsr, argv[2], nName);
   zCsr += nName;
@@ -111731,7 +113077,7 @@ static int fts3InitVtab(
   /* Fill in the azColumn array */
   for(iCol=0; iCol<nCol; iCol++){
     char *z; 
-    int n;
+    int n = 0;
     z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
     memcpy(zCsr, z, n);
     zCsr[n] = '\0';
@@ -111758,15 +113104,16 @@ static int fts3InitVtab(
   }
 
   /* Figure out the page-size for the database. This is required in order to
-  ** estimate the cost of loading large doclists from the database (see 
-  ** function sqlite3Fts3SegReaderCost() for details).
-  */
+  ** estimate the cost of loading large doclists from the database.  */
   fts3DatabasePageSize(&rc, p);
+  p->nNodeSize = p->nPgsz-35;
 
   /* Declare the table schema to SQLite. */
   fts3DeclareVtab(&rc, p);
 
 fts3_init_out:
+  sqlite3_free(zPrefix);
+  sqlite3_free(aFree);
   sqlite3_free(zCompress);
   sqlite3_free(zUncompress);
   sqlite3_free((void *)aCol);
@@ -111777,6 +113124,7 @@ fts3_init_out:
       pTokenizer->pModule->xDestroy(pTokenizer);
     }
   }else{
+    assert( p->pSegments==0 );
     *ppVTab = &p->base;
   }
   return rc;
@@ -111862,6 +113210,23 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
     pInfo->aConstraintUsage[iCons].argvIndex = 1;
     pInfo->aConstraintUsage[iCons].omit = 1;
   } 
+
+  /* Regardless of the strategy selected, FTS can deliver rows in rowid (or
+  ** docid) order. Both ascending and descending are possible. 
+  */
+  if( pInfo->nOrderBy==1 ){
+    struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0];
+    if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){
+      if( pOrder->desc ){
+        pInfo->idxStr = "DESC";
+      }else{
+        pInfo->idxStr = "ASC";
+      }
+      pInfo->orderByConsumed = 1;
+    }
+  }
+
+  assert( p->pSegments==0 );
   return SQLITE_OK;
 }
 
@@ -111897,6 +113262,7 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
   sqlite3Fts3FreeDeferredTokens(pCsr);
   sqlite3_free(pCsr->aDoclist);
   sqlite3_free(pCsr->aMatchinfo);
+  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
   sqlite3_free(pCsr);
   return SQLITE_OK;
 }
@@ -111908,8 +113274,8 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
 */
 static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
   if( pCsr->isRequireSeek ){
-    pCsr->isRequireSeek = 0;
     sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
+    pCsr->isRequireSeek = 0;
     if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
       return SQLITE_OK;
     }else{
@@ -111919,7 +113285,7 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
         ** table is missing a row that is present in the full-text index.
         ** The data structures are corrupt.
         */
-        rc = SQLITE_CORRUPT;
+        rc = SQLITE_CORRUPT_VTAB;
       }
       pCsr->isEof = 1;
       if( pContext ){
@@ -111979,7 +113345,7 @@ static int fts3ScanInteriorNode(
   zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
   zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
   if( zCsr>zEnd ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_VTAB;
   }
   
   while( zCsr<zEnd && (piFirst || piLast) ){
@@ -111997,7 +113363,7 @@ static int fts3ScanInteriorNode(
     zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
     
     if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
-      rc = SQLITE_CORRUPT;
+      rc = SQLITE_CORRUPT_VTAB;
       goto finish_scan;
     }
     if( nPrefix+nSuffix>nAlloc ){
@@ -112090,7 +113456,7 @@ static int fts3SelectLeaf(
     int nBlob;                    /* Size of zBlob in bytes */
 
     if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
-      rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob);
+      rc = sqlite3Fts3ReadBlock(p, *piLeaf, &zBlob, &nBlob, 0);
       if( rc==SQLITE_OK ){
         rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, 0);
       }
@@ -112100,7 +113466,7 @@ static int fts3SelectLeaf(
     }
 
     if( rc==SQLITE_OK ){
-      rc = sqlite3Fts3ReadBlock(p, piLeaf ? *piLeaf : *piLeaf2, &zBlob, &nBlob);
+      rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0);
     }
     if( rc==SQLITE_OK ){
       rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
@@ -112476,7 +113842,19 @@ static int fts3PoslistPhraseMerge(
 }
 
 /*
-** Merge two position-lists as required by the NEAR operator.
+** Merge two position-lists as required by the NEAR operator. The argument
+** position lists correspond to the left and right phrases of an expression 
+** like:
+**
+**     "phrase 1" NEAR "phrase number 2"
+**
+** Position list *pp1 corresponds to the left-hand side of the NEAR 
+** expression and *pp2 to the right. As usual, the indexes in the position 
+** lists are the offsets of the last token in each phrase (tokens "1" and "2" 
+** in the example above).
+**
+** The output position list - written to *pp - is a copy of *pp2 with those
+** entries that are not sufficiently NEAR entries in *pp1 removed.
 */
 static int fts3PoslistNearMerge(
   char **pp,                      /* Output buffer */
@@ -112489,226 +113867,181 @@ static int fts3PoslistNearMerge(
   char *p1 = *pp1;
   char *p2 = *pp2;
 
-  if( !pp ){
-    if( fts3PoslistPhraseMerge(0, nRight, 0, 0, pp1, pp2) ) return 1;
-    *pp1 = p1;
-    *pp2 = p2;
-    return fts3PoslistPhraseMerge(0, nLeft, 0, 0, pp2, pp1);
+  char *pTmp1 = aTmp;
+  char *pTmp2;
+  char *aTmp2;
+  int res = 1;
+
+  fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
+  aTmp2 = pTmp2 = pTmp1;
+  *pp1 = p1;
+  *pp2 = p2;
+  fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
+  if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
+    fts3PoslistMerge(pp, &aTmp, &aTmp2);
+  }else if( pTmp1!=aTmp ){
+    fts3PoslistCopy(pp, &aTmp);
+  }else if( pTmp2!=aTmp2 ){
+    fts3PoslistCopy(pp, &aTmp2);
+  }else{
+    res = 0;
+  }
+
+  return res;
+}
+
+/* 
+** A pointer to an instance of this structure is used as the context 
+** argument to sqlite3Fts3SegReaderIterate()
+*/
+typedef struct TermSelect TermSelect;
+struct TermSelect {
+  int isReqPos;
+  char *aaOutput[16];             /* Malloc'd output buffer */
+  int anOutput[16];               /* Size of output in bytes */
+};
+
+
+static void fts3GetDeltaVarint3(
+  char **pp, 
+  char *pEnd, 
+  int bDescIdx,
+  sqlite3_int64 *pVal
+){
+  if( *pp>=pEnd ){
+    *pp = 0;
   }else{
-    char *pTmp1 = aTmp;
-    char *pTmp2;
-    char *aTmp2;
-    int res = 1;
-
-    fts3PoslistPhraseMerge(&pTmp1, nRight, 0, 0, pp1, pp2);
-    aTmp2 = pTmp2 = pTmp1;
-    *pp1 = p1;
-    *pp2 = p2;
-    fts3PoslistPhraseMerge(&pTmp2, nLeft, 1, 0, pp2, pp1);
-    if( pTmp1!=aTmp && pTmp2!=aTmp2 ){
-      fts3PoslistMerge(pp, &aTmp, &aTmp2);
-    }else if( pTmp1!=aTmp ){
-      fts3PoslistCopy(pp, &aTmp);
-    }else if( pTmp2!=aTmp2 ){
-      fts3PoslistCopy(pp, &aTmp2);
+    sqlite3_int64 iVal;
+    *pp += sqlite3Fts3GetVarint(*pp, &iVal);
+    if( bDescIdx ){
+      *pVal -= iVal;
     }else{
-      res = 0;
+      *pVal += iVal;
     }
+  }
+}
 
-    return res;
+static void fts3PutDeltaVarint3(
+  char **pp,                      /* IN/OUT: Output pointer */
+  int bDescIdx,                   /* True for descending docids */
+  sqlite3_int64 *piPrev,          /* IN/OUT: Previous value written to list */
+  int *pbFirst,                   /* IN/OUT: True after first int written */
+  sqlite3_int64 iVal              /* Write this value to the list */
+){
+  sqlite3_int64 iWrite;
+  if( bDescIdx==0 || *pbFirst==0 ){
+    iWrite = iVal - *piPrev;
+  }else{
+    iWrite = *piPrev - iVal;
   }
+  assert( *pbFirst || *piPrev==0 );
+  assert( *pbFirst==0 || iWrite>0 );
+  *pp += sqlite3Fts3PutVarint(*pp, iWrite);
+  *piPrev = iVal;
+  *pbFirst = 1;
 }
 
-/*
-** Values that may be used as the first parameter to fts3DoclistMerge().
-*/
-#define MERGE_NOT        2        /* D + D -> D */
-#define MERGE_AND        3        /* D + D -> D */
-#define MERGE_OR         4        /* D + D -> D */
-#define MERGE_POS_OR     5        /* P + P -> P */
-#define MERGE_PHRASE     6        /* P + P -> D */
-#define MERGE_POS_PHRASE 7        /* P + P -> P */
-#define MERGE_NEAR       8        /* P + P -> D */
-#define MERGE_POS_NEAR   9        /* P + P -> P */
+#define COMPARE_DOCID(i1, i2) ((bDescIdx?-1:1) * (i1-i2))
 
-/*
-** Merge the two doclists passed in buffer a1 (size n1 bytes) and a2
-** (size n2 bytes). The output is written to pre-allocated buffer aBuffer,
-** which is guaranteed to be large enough to hold the results. The number
-** of bytes written to aBuffer is stored in *pnBuffer before returning.
-**
-** If successful, SQLITE_OK is returned. Otherwise, if a malloc error
-** occurs while allocating a temporary buffer as part of the merge operation,
-** SQLITE_NOMEM is returned.
-*/
-static int fts3DoclistMerge(
-  int mergetype,                  /* One of the MERGE_XXX constants */
-  int nParam1,                    /* Used by MERGE_NEAR and MERGE_POS_NEAR */
-  int nParam2,                    /* Used by MERGE_NEAR and MERGE_POS_NEAR */
-  char *aBuffer,                  /* Pre-allocated output buffer */
-  int *pnBuffer,                  /* OUT: Bytes written to aBuffer */
-  char *a1,                       /* Buffer containing first doclist */
-  int n1,                         /* Size of buffer a1 */
-  char *a2,                       /* Buffer containing second doclist */
-  int n2,                         /* Size of buffer a2 */
-  int *pnDoc                      /* OUT: Number of docids in output */
+static int fts3DoclistOrMerge(
+  int bDescIdx,                   /* True if arguments are desc */
+  char *a1, int n1,               /* First doclist */
+  char *a2, int n2,               /* Second doclist */
+  char **paOut, int *pnOut        /* OUT: Malloc'd doclist */
 ){
   sqlite3_int64 i1 = 0;
   sqlite3_int64 i2 = 0;
   sqlite3_int64 iPrev = 0;
-
-  char *p = aBuffer;
-  char *p1 = a1;
-  char *p2 = a2;
   char *pEnd1 = &a1[n1];
   char *pEnd2 = &a2[n2];
-  int nDoc = 0;
-
-  assert( mergetype==MERGE_OR     || mergetype==MERGE_POS_OR 
-       || mergetype==MERGE_AND    || mergetype==MERGE_NOT
-       || mergetype==MERGE_PHRASE || mergetype==MERGE_POS_PHRASE
-       || mergetype==MERGE_NEAR   || mergetype==MERGE_POS_NEAR
-  );
-
-  if( !aBuffer ){
-    *pnBuffer = 0;
-    return SQLITE_NOMEM;
-  }
-
-  /* Read the first docid from each doclist */
-  fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-  fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-
-  switch( mergetype ){
-    case MERGE_OR:
-    case MERGE_POS_OR:
-      while( p1 || p2 ){
-        if( p2 && p1 && i1==i2 ){
-          fts3PutDeltaVarint(&p, &iPrev, i1);
-          if( mergetype==MERGE_POS_OR ) fts3PoslistMerge(&p, &p1, &p2);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }else if( !p2 || (p1 && i1<i2) ){
-          fts3PutDeltaVarint(&p, &iPrev, i1);
-          if( mergetype==MERGE_POS_OR ) fts3PoslistCopy(&p, &p1);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-        }else{
-          fts3PutDeltaVarint(&p, &iPrev, i2);
-          if( mergetype==MERGE_POS_OR ) fts3PoslistCopy(&p, &p2);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }
-      }
-      break;
-
-    case MERGE_AND:
-      while( p1 && p2 ){
-        if( i1==i2 ){
-          fts3PutDeltaVarint(&p, &iPrev, i1);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-          nDoc++;
-        }else if( i1<i2 ){
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-        }else{
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }
-      }
-      break;
-
-    case MERGE_NOT:
-      while( p1 ){
-        if( p2 && i1==i2 ){
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }else if( !p2 || i1<i2 ){
-          fts3PutDeltaVarint(&p, &iPrev, i1);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-        }else{
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }
-      }
-      break;
+  char *p1 = a1;
+  char *p2 = a2;
+  char *p;
+  char *aOut;
+  int bFirstOut = 0;
 
-    case MERGE_POS_PHRASE:
-    case MERGE_PHRASE: {
-      char **ppPos = (mergetype==MERGE_PHRASE ? 0 : &p);
-      while( p1 && p2 ){
-        if( i1==i2 ){
-          char *pSave = p;
-          sqlite3_int64 iPrevSave = iPrev;
-          fts3PutDeltaVarint(&p, &iPrev, i1);
-          if( 0==fts3PoslistPhraseMerge(ppPos, nParam1, 0, 1, &p1, &p2) ){
-            p = pSave;
-            iPrev = iPrevSave;
-          }else{
-            nDoc++;
-          }
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }else if( i1<i2 ){
-          fts3PoslistCopy(0, &p1);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-        }else{
-          fts3PoslistCopy(0, &p2);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }
-      }
-      break;
+  *paOut = 0;
+  *pnOut = 0;
+  aOut = sqlite3_malloc(n1+n2);
+  if( !aOut ) return SQLITE_NOMEM;
+
+  p = aOut;
+  fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
+  fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
+  while( p1 || p2 ){
+    sqlite3_int64 iDiff = COMPARE_DOCID(i1, i2);
+
+    if( p2 && p1 && iDiff==0 ){
+      fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1);
+      fts3PoslistMerge(&p, &p1, &p2);
+      fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1);
+      fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2);
+    }else if( !p2 || (p1 && iDiff<0) ){
+      fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1);
+      fts3PoslistCopy(&p, &p1);
+      fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1);
+    }else{
+      fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i2);
+      fts3PoslistCopy(&p, &p2);
+      fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2);
     }
+  }
 
-    default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); {
-      char *aTmp = 0;
-      char **ppPos = 0;
-
-      if( mergetype==MERGE_POS_NEAR ){
-        ppPos = &p;
-        aTmp = sqlite3_malloc(2*(n1+n2+1));
-        if( !aTmp ){
-          return SQLITE_NOMEM;
-        }
-      }
-
-      while( p1 && p2 ){
-        if( i1==i2 ){
-          char *pSave = p;
-          sqlite3_int64 iPrevSave = iPrev;
-          fts3PutDeltaVarint(&p, &iPrev, i1);
+  *paOut = aOut;
+  *pnOut = (p-aOut);
+  return SQLITE_OK;
+}
 
-          if( !fts3PoslistNearMerge(ppPos, aTmp, nParam1, nParam2, &p1, &p2) ){
-            iPrev = iPrevSave;
-            p = pSave;
-          }
+static void fts3DoclistPhraseMerge(
+  int bDescIdx,                   /* True if arguments are desc */
+  int nDist,                      /* Distance from left to right (1=adjacent) */
+  char *aLeft, int nLeft,         /* Left doclist */
+  char *aRight, int *pnRight      /* IN/OUT: Right/output doclist */
+){
+  sqlite3_int64 i1 = 0;
+  sqlite3_int64 i2 = 0;
+  sqlite3_int64 iPrev = 0;
+  char *pEnd1 = &aLeft[nLeft];
+  char *pEnd2 = &aRight[*pnRight];
+  char *p1 = aLeft;
+  char *p2 = aRight;
+  char *p;
+  int bFirstOut = 0;
+  char *aOut = aRight;
+
+  assert( nDist>0 );
+
+  p = aOut;
+  fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1);
+  fts3GetDeltaVarint3(&p2, pEnd2, 0, &i2);
+
+  while( p1 && p2 ){
+    sqlite3_int64 iDiff = COMPARE_DOCID(i1, i2);
+    if( iDiff==0 ){
+      char *pSave = p;
+      sqlite3_int64 iPrevSave = iPrev;
+      int bFirstOutSave = bFirstOut;
 
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }else if( i1<i2 ){
-          fts3PoslistCopy(0, &p1);
-          fts3GetDeltaVarint2(&p1, pEnd1, &i1);
-        }else{
-          fts3PoslistCopy(0, &p2);
-          fts3GetDeltaVarint2(&p2, pEnd2, &i2);
-        }
-      }
-      sqlite3_free(aTmp);
-      break;
+      fts3PutDeltaVarint3(&p, bDescIdx, &iPrev, &bFirstOut, i1);
+      if( 0==fts3PoslistPhraseMerge(&p, nDist, 0, 1, &p1, &p2) ){
+        p = pSave;
+        iPrev = iPrevSave;
+        bFirstOut = bFirstOutSave;
+      }
+      fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1);
+      fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2);
+    }else if( iDiff<0 ){
+      fts3PoslistCopy(0, &p1);
+      fts3GetDeltaVarint3(&p1, pEnd1, bDescIdx, &i1);
+    }else{
+      fts3PoslistCopy(0, &p2);
+      fts3GetDeltaVarint3(&p2, pEnd2, bDescIdx, &i2);
     }
   }
 
-  if( pnDoc ) *pnDoc = nDoc;
-  *pnBuffer = (int)(p-aBuffer);
-  return SQLITE_OK;
+  *pnRight = p - aOut;
 }
 
-/* 
-** A pointer to an instance of this structure is used as the context 
-** argument to sqlite3Fts3SegReaderIterate()
-*/
-typedef struct TermSelect TermSelect;
-struct TermSelect {
-  int isReqPos;
-  char *aaOutput[16];             /* Malloc'd output buffer */
-  int anOutput[16];               /* Size of output in bytes */
-};
 
 /*
 ** Merge all doclists in the TermSelect.aaOutput[] array into a single
@@ -112719,8 +114052,7 @@ struct TermSelect {
 ** the responsibility of the caller to free any doclists left in the
 ** TermSelect.aaOutput[] array.
 */
-static int fts3TermSelectMerge(TermSelect *pTS){
-  int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
+static int fts3TermSelectMerge(Fts3Table *p, TermSelect *pTS){
   char *aOut = 0;
   int nOut = 0;
   int i;
@@ -112735,15 +114067,17 @@ static int fts3TermSelectMerge(TermSelect *pTS){
         nOut = pTS->anOutput[i];
         pTS->aaOutput[i] = 0;
       }else{
-        int nNew = nOut + pTS->anOutput[i];
-        char *aNew = sqlite3_malloc(nNew);
-        if( !aNew ){
+        int nNew;
+        char *aNew;
+
+        int rc = fts3DoclistOrMerge(p->bDescIdx, 
+            pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew
+        );
+        if( rc!=SQLITE_OK ){
           sqlite3_free(aOut);
-          return SQLITE_NOMEM;
+          return rc;
         }
-        fts3DoclistMerge(mergetype, 0, 0,
-            aNew, &nNew, pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, 0
-        );
+
         sqlite3_free(pTS->aaOutput[i]);
         sqlite3_free(aOut);
         pTS->aaOutput[i] = 0;
@@ -112779,9 +114113,7 @@ static int fts3TermSelectCb(
 
   if( pTS->aaOutput[0]==0 ){
     /* If this is the first term selected, copy the doclist to the output
-    ** buffer using memcpy(). TODO: Add a way to transfer control of the
-    ** aDoclist buffer from the caller so as to avoid the memcpy().
-    */
+    ** buffer using memcpy(). */
     pTS->aaOutput[0] = sqlite3_malloc(nDoclist);
     pTS->anOutput[0] = nDoclist;
     if( pTS->aaOutput[0] ){
@@ -112790,126 +114122,100 @@ static int fts3TermSelectCb(
       return SQLITE_NOMEM;
     }
   }else{
-    int mergetype = (pTS->isReqPos ? MERGE_POS_OR : MERGE_OR);
     char *aMerge = aDoclist;
     int nMerge = nDoclist;
     int iOut;
 
     for(iOut=0; iOut<SizeofArray(pTS->aaOutput); iOut++){
-      char *aNew;
-      int nNew;
       if( pTS->aaOutput[iOut]==0 ){
         assert( iOut>0 );
         pTS->aaOutput[iOut] = aMerge;
         pTS->anOutput[iOut] = nMerge;
         break;
-      }
+      }else{
+        char *aNew;
+        int nNew;
 
-      nNew = nMerge + pTS->anOutput[iOut];
-      aNew = sqlite3_malloc(nNew);
-      if( !aNew ){
-        if( aMerge!=aDoclist ){
-          sqlite3_free(aMerge);
+        int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge, 
+            pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew
+        );
+        if( rc!=SQLITE_OK ){
+          if( aMerge!=aDoclist ) sqlite3_free(aMerge);
+          return rc;
         }
-        return SQLITE_NOMEM;
-      }
-      fts3DoclistMerge(mergetype, 0, 0, aNew, &nNew, 
-          pTS->aaOutput[iOut], pTS->anOutput[iOut], aMerge, nMerge, 0
-      );
 
-      if( iOut>0 ) sqlite3_free(aMerge);
-      sqlite3_free(pTS->aaOutput[iOut]);
-      pTS->aaOutput[iOut] = 0;
-
-      aMerge = aNew;
-      nMerge = nNew;
-      if( (iOut+1)==SizeofArray(pTS->aaOutput) ){
-        pTS->aaOutput[iOut] = aMerge;
-        pTS->anOutput[iOut] = nMerge;
+        if( aMerge!=aDoclist ) sqlite3_free(aMerge);
+        sqlite3_free(pTS->aaOutput[iOut]);
+        pTS->aaOutput[iOut] = 0;
+  
+        aMerge = aNew;
+        nMerge = nNew;
+        if( (iOut+1)==SizeofArray(pTS->aaOutput) ){
+          pTS->aaOutput[iOut] = aMerge;
+          pTS->anOutput[iOut] = nMerge;
+        }
       }
     }
   }
   return SQLITE_OK;
 }
 
-static int fts3DeferredTermSelect(
-  Fts3DeferredToken *pToken,      /* Phrase token */
-  int isTermPos,                  /* True to include positions */
-  int *pnOut,                     /* OUT: Size of list */
-  char **ppOut                    /* OUT: Body of list */
-){
-  char *aSource;
-  int nSource;
-
-  aSource = sqlite3Fts3DeferredDoclist(pToken, &nSource);
-  if( !aSource ){
-    *pnOut = 0;
-    *ppOut = 0;
-  }else if( isTermPos ){
-    *ppOut = sqlite3_malloc(nSource);
-    if( !*ppOut ) return SQLITE_NOMEM;
-    memcpy(*ppOut, aSource, nSource);
-    *pnOut = nSource;
-  }else{
-    sqlite3_int64 docid;
-    *pnOut = sqlite3Fts3GetVarint(aSource, &docid);
-    *ppOut = sqlite3_malloc(*pnOut);
-    if( !*ppOut ) return SQLITE_NOMEM;
-    sqlite3Fts3PutVarint(*ppOut, docid);
+/*
+** Append SegReader object pNew to the end of the pCsr->apSegment[] array.
+*/
+static int fts3SegReaderCursorAppend(
+  Fts3MultiSegReader *pCsr, 
+  Fts3SegReader *pNew
+){
+  if( (pCsr->nSegment%16)==0 ){
+    Fts3SegReader **apNew;
+    int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
+    apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte);
+    if( !apNew ){
+      sqlite3Fts3SegReaderFree(pNew);
+      return SQLITE_NOMEM;
+    }
+    pCsr->apSegment = apNew;
   }
-
+  pCsr->apSegment[pCsr->nSegment++] = pNew;
   return SQLITE_OK;
 }
 
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
+static int fts3SegReaderCursor(
   Fts3Table *p,                   /* FTS3 table handle */
+  int iIndex,                     /* Index to search (from 0 to p->nIndex-1) */
   int iLevel,                     /* Level of segments to scan */
   const char *zTerm,              /* Term to query for */
   int nTerm,                      /* Size of zTerm in bytes */
   int isPrefix,                   /* True for a prefix search */
   int isScan,                     /* True to scan from zTerm to EOF */
-  Fts3SegReaderCursor *pCsr       /* Cursor object to populate */
+  Fts3MultiSegReader *pCsr       /* Cursor object to populate */
 ){
   int rc = SQLITE_OK;
   int rc2;
-  int iAge = 0;
   sqlite3_stmt *pStmt = 0;
-  Fts3SegReader *pPending = 0;
-
-  assert( iLevel==FTS3_SEGCURSOR_ALL 
-      ||  iLevel==FTS3_SEGCURSOR_PENDING 
-      ||  iLevel>=0
-  );
-  assert( FTS3_SEGCURSOR_PENDING<0 );
-  assert( FTS3_SEGCURSOR_ALL<0 );
-  assert( iLevel==FTS3_SEGCURSOR_ALL || (zTerm==0 && isPrefix==1) );
-  assert( isPrefix==0 || isScan==0 );
-
-
-  memset(pCsr, 0, sizeof(Fts3SegReaderCursor));
 
-  /* If iLevel is less than 0, include a seg-reader for the pending-terms. */
-  assert( isScan==0 || fts3HashCount(&p->pendingTerms)==0 );
-  if( iLevel<0 && isScan==0 ){
-    rc = sqlite3Fts3SegReaderPending(p, zTerm, nTerm, isPrefix, &pPending);
-    if( rc==SQLITE_OK && pPending ){
-      int nByte = (sizeof(Fts3SegReader *) * 16);
-      pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte);
-      if( pCsr->apSegment==0 ){
-        rc = SQLITE_NOMEM;
-      }else{
-        pCsr->apSegment[0] = pPending;
-        pCsr->nSegment = 1;
-        pPending = 0;
-      }
+  /* If iLevel is less than 0 and this is not a scan, include a seg-reader 
+  ** for the pending-terms. If this is a scan, then this call must be being
+  ** made by an fts4aux module, not an FTS table. In this case calling
+  ** Fts3SegReaderPending might segfault, as the data structures used by 
+  ** fts4aux are not completely populated. So it's easiest to filter these
+  ** calls out here.  */
+  if( iLevel<0 && p->aIndex ){
+    Fts3SegReader *pSeg = 0;
+    rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix, &pSeg);
+    if( rc==SQLITE_OK && pSeg ){
+      rc = fts3SegReaderCursorAppend(pCsr, pSeg);
     }
   }
 
   if( iLevel!=FTS3_SEGCURSOR_PENDING ){
     if( rc==SQLITE_OK ){
-      rc = sqlite3Fts3AllSegdirs(p, iLevel, &pStmt);
+      rc = sqlite3Fts3AllSegdirs(p, iIndex, iLevel, &pStmt);
     }
+
     while( rc==SQLITE_OK && SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
+      Fts3SegReader *pSeg = 0;
 
       /* Read the values returned by the SELECT into local variables. */
       sqlite3_int64 iStartBlock = sqlite3_column_int64(pStmt, 1);
@@ -112918,18 +114224,6 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
       int nRoot = sqlite3_column_bytes(pStmt, 4);
       char const *zRoot = sqlite3_column_blob(pStmt, 4);
 
-      /* If nSegment is a multiple of 16 the array needs to be extended. */
-      if( (pCsr->nSegment%16)==0 ){
-        Fts3SegReader **apNew;
-        int nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
-        apNew = (Fts3SegReader **)sqlite3_realloc(pCsr->apSegment, nByte);
-        if( !apNew ){
-          rc = SQLITE_NOMEM;
-          goto finished;
-        }
-        pCsr->apSegment = apNew;
-      }
-
       /* If zTerm is not NULL, and this segment is not stored entirely on its
       ** root node, the range of leaves scanned can be reduced. Do this. */
       if( iStartBlock && zTerm ){
@@ -112939,53 +114233,117 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
         if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock;
       }
  
-      rc = sqlite3Fts3SegReaderNew(iAge, iStartBlock, iLeavesEndBlock,
-          iEndBlock, zRoot, nRoot, &pCsr->apSegment[pCsr->nSegment]
+      rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1, 
+          iStartBlock, iLeavesEndBlock, iEndBlock, zRoot, nRoot, &pSeg
       );
       if( rc!=SQLITE_OK ) goto finished;
-      pCsr->nSegment++;
-      iAge++;
+      rc = fts3SegReaderCursorAppend(pCsr, pSeg);
     }
   }
 
  finished:
   rc2 = sqlite3_reset(pStmt);
   if( rc==SQLITE_DONE ) rc = rc2;
-  sqlite3Fts3SegReaderFree(pPending);
 
   return rc;
 }
 
+/*
+** Set up a cursor object for iterating through a full-text index or a 
+** single level therein.
+*/
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
+  Fts3Table *p,                   /* FTS3 table handle */
+  int iIndex,                     /* Index to search (from 0 to p->nIndex-1) */
+  int iLevel,                     /* Level of segments to scan */
+  const char *zTerm,              /* Term to query for */
+  int nTerm,                      /* Size of zTerm in bytes */
+  int isPrefix,                   /* True for a prefix search */
+  int isScan,                     /* True to scan from zTerm to EOF */
+  Fts3MultiSegReader *pCsr       /* Cursor object to populate */
+){
+  assert( iIndex>=0 && iIndex<p->nIndex );
+  assert( iLevel==FTS3_SEGCURSOR_ALL
+      ||  iLevel==FTS3_SEGCURSOR_PENDING 
+      ||  iLevel>=0
+  );
+  assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
+  assert( FTS3_SEGCURSOR_ALL<0 && FTS3_SEGCURSOR_PENDING<0 );
+  assert( isPrefix==0 || isScan==0 );
+
+  /* "isScan" is only set to true by the ft4aux module, an ordinary
+  ** full-text tables. */
+  assert( isScan==0 || p->aIndex==0 );
+
+  memset(pCsr, 0, sizeof(Fts3MultiSegReader));
+
+  return fts3SegReaderCursor(
+      p, iIndex, iLevel, zTerm, nTerm, isPrefix, isScan, pCsr
+  );
+}
+
+static int fts3SegReaderCursorAddZero(
+  Fts3Table *p,
+  const char *zTerm,
+  int nTerm,
+  Fts3MultiSegReader *pCsr
+){
+  return fts3SegReaderCursor(p, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr);
+}
+
 
-static int fts3TermSegReaderCursor(
+SQLITE_PRIVATE int sqlite3Fts3TermSegReaderCursor(
   Fts3Cursor *pCsr,               /* Virtual table cursor handle */
   const char *zTerm,              /* Term to query for */
   int nTerm,                      /* Size of zTerm in bytes */
   int isPrefix,                   /* True for a prefix search */
-  Fts3SegReaderCursor **ppSegcsr  /* OUT: Allocated seg-reader cursor */
+  Fts3MultiSegReader **ppSegcsr   /* OUT: Allocated seg-reader cursor */
 ){
-  Fts3SegReaderCursor *pSegcsr;   /* Object to allocate and return */
+  Fts3MultiSegReader *pSegcsr;   /* Object to allocate and return */
   int rc = SQLITE_NOMEM;          /* Return code */
 
-  pSegcsr = sqlite3_malloc(sizeof(Fts3SegReaderCursor));
+  pSegcsr = sqlite3_malloc(sizeof(Fts3MultiSegReader));
   if( pSegcsr ){
-    Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
     int i;
-    int nCost = 0;
-    rc = sqlite3Fts3SegReaderCursor(
-        p, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr);
-  
-    for(i=0; rc==SQLITE_OK && i<pSegcsr->nSegment; i++){
-      rc = sqlite3Fts3SegReaderCost(pCsr, pSegcsr->apSegment[i], &nCost);
+    int bFound = 0;               /* True once an index has been found */
+    Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+
+    if( isPrefix ){
+      for(i=1; bFound==0 && i<p->nIndex; i++){
+        if( p->aIndex[i].nPrefix==nTerm ){
+          bFound = 1;
+          rc = sqlite3Fts3SegReaderCursor(
+              p, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr);
+          pSegcsr->bLookup = 1;
+        }
+      }
+
+      for(i=1; bFound==0 && i<p->nIndex; i++){
+        if( p->aIndex[i].nPrefix==nTerm+1 ){
+          bFound = 1;
+          rc = sqlite3Fts3SegReaderCursor(
+              p, i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
+          );
+          if( rc==SQLITE_OK ){
+            rc = fts3SegReaderCursorAddZero(p, zTerm, nTerm, pSegcsr);
+          }
+        }
+      }
+    }
+
+    if( bFound==0 ){
+      rc = sqlite3Fts3SegReaderCursor(
+          p, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
+      );
+      pSegcsr->bLookup = !isPrefix;
     }
-    pSegcsr->nCost = nCost;
   }
 
   *ppSegcsr = pSegcsr;
   return rc;
 }
 
-static void fts3SegReaderCursorFree(Fts3SegReaderCursor *pSegcsr){
+static void fts3SegReaderCursorFree(Fts3MultiSegReader *pSegcsr){
   sqlite3Fts3SegReaderFinish(pSegcsr);
   sqlite3_free(pSegcsr);
 }
@@ -113010,7 +114368,7 @@ static int fts3TermSelect(
   char **ppOut                    /* OUT: Malloced result buffer */
 ){
   int rc;                         /* Return code */
-  Fts3SegReaderCursor *pSegcsr;   /* Seg-reader cursor for this term */
+  Fts3MultiSegReader *pSegcsr;   /* Seg-reader cursor for this term */
   TermSelect tsc;                 /* Context object for fts3TermSelectCb() */
   Fts3SegFilter filter;           /* Segment term filter configuration */
 
@@ -113036,7 +114394,7 @@ static int fts3TermSelect(
   }
 
   if( rc==SQLITE_OK ){
-    rc = fts3TermSelectMerge(&tsc);
+    rc = fts3TermSelectMerge(p, &tsc);
   }
   if( rc==SQLITE_OK ){
     *ppOut = tsc.aaOutput[0];
@@ -113086,660 +114444,6 @@ static int fts3DoclistCountDocids(int isPoslist, char *aList, int nList){
   return nDoc;
 }
 
-/*
-** Call sqlite3Fts3DeferToken() for each token in the expression pExpr.
-*/
-static int fts3DeferExpression(Fts3Cursor *pCsr, Fts3Expr *pExpr){
-  int rc = SQLITE_OK;
-  if( pExpr ){
-    rc = fts3DeferExpression(pCsr, pExpr->pLeft);
-    if( rc==SQLITE_OK ){
-      rc = fts3DeferExpression(pCsr, pExpr->pRight);
-    }
-    if( pExpr->eType==FTSQUERY_PHRASE ){
-      int iCol = pExpr->pPhrase->iColumn;
-      int i;
-      for(i=0; rc==SQLITE_OK && i<pExpr->pPhrase->nToken; i++){
-        Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
-        if( pToken->pDeferred==0 ){
-          rc = sqlite3Fts3DeferToken(pCsr, pToken, iCol);
-        }
-      }
-    }
-  }
-  return rc;
-}
-
-/*
-** This function removes the position information from a doclist. When
-** called, buffer aList (size *pnList bytes) contains a doclist that includes
-** position information. This function removes the position information so
-** that aList contains only docids, and adjusts *pnList to reflect the new
-** (possibly reduced) size of the doclist.
-*/
-static void fts3DoclistStripPositions(
-  char *aList,                    /* IN/OUT: Buffer containing doclist */
-  int *pnList                     /* IN/OUT: Size of doclist in bytes */
-){
-  if( aList ){
-    char *aEnd = &aList[*pnList]; /* Pointer to one byte after EOF */
-    char *p = aList;              /* Input cursor */
-    char *pOut = aList;           /* Output cursor */
-  
-    while( p<aEnd ){
-      sqlite3_int64 delta;
-      p += sqlite3Fts3GetVarint(p, &delta);
-      fts3PoslistCopy(0, &p);
-      pOut += sqlite3Fts3PutVarint(pOut, delta);
-    }
-
-    *pnList = (int)(pOut - aList);
-  }
-}
-
-/* 
-** Return a DocList corresponding to the phrase *pPhrase.
-**
-** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
-** then no tokens in the phrase were looked up in the full-text index. This
-** is only possible when this function is called from within xFilter(). The
-** caller should assume that all documents match the phrase. The actual
-** filtering will take place in xNext().
-*/
-static int fts3PhraseSelect(
-  Fts3Cursor *pCsr,               /* Virtual table cursor handle */
-  Fts3Phrase *pPhrase,            /* Phrase to return a doclist for */
-  int isReqPos,                   /* True if output should contain positions */
-  char **paOut,                   /* OUT: Pointer to malloc'd result buffer */
-  int *pnOut                      /* OUT: Size of buffer at *paOut */
-){
-  char *pOut = 0;
-  int nOut = 0;
-  int rc = SQLITE_OK;
-  int ii;
-  int iCol = pPhrase->iColumn;
-  int isTermPos = (pPhrase->nToken>1 || isReqPos);
-  Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
-  int isFirst = 1;
-
-  int iPrevTok = 0;
-  int nDoc = 0;
-
-  /* If this is an xFilter() evaluation, create a segment-reader for each
-  ** phrase token. Or, if this is an xNext() or snippet/offsets/matchinfo
-  ** evaluation, only create segment-readers if there are no Fts3DeferredToken
-  ** objects attached to the phrase-tokens.
-  */
-  for(ii=0; ii<pPhrase->nToken; ii++){
-    Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
-    if( pTok->pSegcsr==0 ){
-      if( (pCsr->eEvalmode==FTS3_EVAL_FILTER)
-       || (pCsr->eEvalmode==FTS3_EVAL_NEXT && pCsr->pDeferred==0) 
-       || (pCsr->eEvalmode==FTS3_EVAL_MATCHINFO && pTok->bFulltext) 
-      ){
-        rc = fts3TermSegReaderCursor(
-            pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pSegcsr
-        );
-        if( rc!=SQLITE_OK ) return rc;
-      }
-    }
-  }
-
-  for(ii=0; ii<pPhrase->nToken; ii++){
-    Fts3PhraseToken *pTok;        /* Token to find doclist for */
-    int iTok = 0;                 /* The token being queried this iteration */
-    char *pList = 0;              /* Pointer to token doclist */
-    int nList = 0;                /* Size of buffer at pList */
-
-    /* Select a token to process. If this is an xFilter() call, then tokens 
-    ** are processed in order from least to most costly. Otherwise, tokens 
-    ** are processed in the order in which they occur in the phrase.
-    */
-    if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
-      assert( isReqPos );
-      iTok = ii;
-      pTok = &pPhrase->aToken[iTok];
-      if( pTok->bFulltext==0 ) continue;
-    }else if( pCsr->eEvalmode==FTS3_EVAL_NEXT || isReqPos ){
-      iTok = ii;
-      pTok = &pPhrase->aToken[iTok];
-    }else{
-      int nMinCost = 0x7FFFFFFF;
-      int jj;
-
-      /* Find the remaining token with the lowest cost. */
-      for(jj=0; jj<pPhrase->nToken; jj++){
-        Fts3SegReaderCursor *pSegcsr = pPhrase->aToken[jj].pSegcsr;
-        if( pSegcsr && pSegcsr->nCost<nMinCost ){
-          iTok = jj;
-          nMinCost = pSegcsr->nCost;
-        }
-      }
-      pTok = &pPhrase->aToken[iTok];
-
-      /* This branch is taken if it is determined that loading the doclist
-      ** for the next token would require more IO than loading all documents
-      ** currently identified by doclist pOut/nOut. No further doclists will
-      ** be loaded from the full-text index for this phrase.
-      */
-      if( nMinCost>nDoc && ii>0 ){
-        rc = fts3DeferExpression(pCsr, pCsr->pExpr);
-        break;
-      }
-    }
-
-    if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
-      rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
-    }else{
-      if( pTok->pSegcsr ){
-        rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
-      }
-      pTok->bFulltext = 1;
-    }
-    assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pSegcsr==0 );
-    if( rc!=SQLITE_OK ) break;
-
-    if( isFirst ){
-      pOut = pList;
-      nOut = nList;
-      if( pCsr->eEvalmode==FTS3_EVAL_FILTER && pPhrase->nToken>1 ){
-        nDoc = fts3DoclistCountDocids(1, pOut, nOut);
-      }
-      isFirst = 0;
-      iPrevTok = iTok;
-    }else{
-      /* Merge the new term list and the current output. */
-      char *aLeft, *aRight;
-      int nLeft, nRight;
-      int nDist;
-      int mt;
-
-      /* If this is the final token of the phrase, and positions were not
-      ** requested by the caller, use MERGE_PHRASE instead of POS_PHRASE.
-      ** This drops the position information from the output list.
-      */
-      mt = MERGE_POS_PHRASE;
-      if( ii==pPhrase->nToken-1 && !isReqPos ) mt = MERGE_PHRASE;
-
-      assert( iPrevTok!=iTok );
-      if( iPrevTok<iTok ){
-        aLeft = pOut;
-        nLeft = nOut;
-        aRight = pList;
-        nRight = nList;
-        nDist = iTok-iPrevTok;
-        iPrevTok = iTok;
-      }else{
-        aRight = pOut;
-        nRight = nOut;
-        aLeft = pList;
-        nLeft = nList;
-        nDist = iPrevTok-iTok;
-      }
-      pOut = aRight;
-      fts3DoclistMerge(
-          mt, nDist, 0, pOut, &nOut, aLeft, nLeft, aRight, nRight, &nDoc
-      );
-      sqlite3_free(aLeft);
-    }
-    assert( nOut==0 || pOut!=0 );
-  }
-
-  if( rc==SQLITE_OK ){
-    if( ii!=pPhrase->nToken ){
-      assert( pCsr->eEvalmode==FTS3_EVAL_FILTER && isReqPos==0 );
-      fts3DoclistStripPositions(pOut, &nOut);
-    }
-    *paOut = pOut;
-    *pnOut = nOut;
-  }else{
-    sqlite3_free(pOut);
-  }
-  return rc;
-}
-
-/*
-** This function merges two doclists according to the requirements of a
-** NEAR operator.
-**
-** Both input doclists must include position information. The output doclist 
-** includes position information if the first argument to this function
-** is MERGE_POS_NEAR, or does not if it is MERGE_NEAR.
-*/
-static int fts3NearMerge(
-  int mergetype,                  /* MERGE_POS_NEAR or MERGE_NEAR */
-  int nNear,                      /* Parameter to NEAR operator */
-  int nTokenLeft,                 /* Number of tokens in LHS phrase arg */
-  char *aLeft,                    /* Doclist for LHS (incl. positions) */
-  int nLeft,                      /* Size of LHS doclist in bytes */
-  int nTokenRight,                /* As nTokenLeft */
-  char *aRight,                   /* As aLeft */
-  int nRight,                     /* As nRight */
-  char **paOut,                   /* OUT: Results of merge (malloced) */
-  int *pnOut                      /* OUT: Sized of output buffer */
-){
-  char *aOut;                     /* Buffer to write output doclist to */
-  int rc;                         /* Return code */
-
-  assert( mergetype==MERGE_POS_NEAR || MERGE_NEAR );
-
-  aOut = sqlite3_malloc(nLeft+nRight+1);
-  if( aOut==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    rc = fts3DoclistMerge(mergetype, nNear+nTokenRight, nNear+nTokenLeft, 
-      aOut, pnOut, aLeft, nLeft, aRight, nRight, 0
-    );
-    if( rc!=SQLITE_OK ){
-      sqlite3_free(aOut);
-      aOut = 0;
-    }
-  }
-
-  *paOut = aOut;
-  return rc;
-}
-
-/*
-** This function is used as part of the processing for the snippet() and
-** offsets() functions.
-**
-** Both pLeft and pRight are expression nodes of type FTSQUERY_PHRASE. Both
-** have their respective doclists (including position information) loaded
-** in Fts3Expr.aDoclist/nDoclist. This function removes all entries from
-** each doclist that are not within nNear tokens of a corresponding entry
-** in the other doclist.
-*/
-SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
-  int rc;                         /* Return code */
-
-  assert( pLeft->eType==FTSQUERY_PHRASE );
-  assert( pRight->eType==FTSQUERY_PHRASE );
-  assert( pLeft->isLoaded && pRight->isLoaded );
-
-  if( pLeft->aDoclist==0 || pRight->aDoclist==0 ){
-    sqlite3_free(pLeft->aDoclist);
-    sqlite3_free(pRight->aDoclist);
-    pRight->aDoclist = 0;
-    pLeft->aDoclist = 0;
-    rc = SQLITE_OK;
-  }else{
-    char *aOut;                   /* Buffer in which to assemble new doclist */
-    int nOut;                     /* Size of buffer aOut in bytes */
-
-    rc = fts3NearMerge(MERGE_POS_NEAR, nNear, 
-        pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
-        pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
-        &aOut, &nOut
-    );
-    if( rc!=SQLITE_OK ) return rc;
-    sqlite3_free(pRight->aDoclist);
-    pRight->aDoclist = aOut;
-    pRight->nDoclist = nOut;
-
-    rc = fts3NearMerge(MERGE_POS_NEAR, nNear, 
-        pRight->pPhrase->nToken, pRight->aDoclist, pRight->nDoclist,
-        pLeft->pPhrase->nToken, pLeft->aDoclist, pLeft->nDoclist,
-        &aOut, &nOut
-    );
-    sqlite3_free(pLeft->aDoclist);
-    pLeft->aDoclist = aOut;
-    pLeft->nDoclist = nOut;
-  }
-  return rc;
-}
-
-
-/*
-** Allocate an Fts3SegReaderArray for each token in the expression pExpr. 
-** The allocated objects are stored in the Fts3PhraseToken.pArray member
-** variables of each token structure.
-*/
-static int fts3ExprAllocateSegReaders(
-  Fts3Cursor *pCsr,               /* FTS3 table */
-  Fts3Expr *pExpr,                /* Expression to create seg-readers for */
-  int *pnExpr                     /* OUT: Number of AND'd expressions */
-){
-  int rc = SQLITE_OK;             /* Return code */
-
-  assert( pCsr->eEvalmode==FTS3_EVAL_FILTER );
-  if( pnExpr && pExpr->eType!=FTSQUERY_AND ){
-    (*pnExpr)++;
-    pnExpr = 0;
-  }
-
-  if( pExpr->eType==FTSQUERY_PHRASE ){
-    Fts3Phrase *pPhrase = pExpr->pPhrase;
-    int ii;
-
-    for(ii=0; rc==SQLITE_OK && ii<pPhrase->nToken; ii++){
-      Fts3PhraseToken *pTok = &pPhrase->aToken[ii];
-      if( pTok->pSegcsr==0 ){
-        rc = fts3TermSegReaderCursor(
-            pCsr, pTok->z, pTok->n, pTok->isPrefix, &pTok->pSegcsr
-        );
-      }
-    }
-  }else{ 
-    rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pLeft, pnExpr);
-    if( rc==SQLITE_OK ){
-      rc = fts3ExprAllocateSegReaders(pCsr, pExpr->pRight, pnExpr);
-    }
-  }
-  return rc;
-}
-
-/*
-** Free the Fts3SegReaderArray objects associated with each token in the
-** expression pExpr. In other words, this function frees the resources
-** allocated by fts3ExprAllocateSegReaders().
-*/
-static void fts3ExprFreeSegReaders(Fts3Expr *pExpr){
-  if( pExpr ){
-    Fts3Phrase *pPhrase = pExpr->pPhrase;
-    if( pPhrase ){
-      int kk;
-      for(kk=0; kk<pPhrase->nToken; kk++){
-        fts3SegReaderCursorFree(pPhrase->aToken[kk].pSegcsr);
-        pPhrase->aToken[kk].pSegcsr = 0;
-      }
-    }
-    fts3ExprFreeSegReaders(pExpr->pLeft);
-    fts3ExprFreeSegReaders(pExpr->pRight);
-  }
-}
-
-/*
-** Return the sum of the costs of all tokens in the expression pExpr. This
-** function must be called after Fts3SegReaderArrays have been allocated
-** for all tokens using fts3ExprAllocateSegReaders().
-*/
-static int fts3ExprCost(Fts3Expr *pExpr){
-  int nCost;                      /* Return value */
-  if( pExpr->eType==FTSQUERY_PHRASE ){
-    Fts3Phrase *pPhrase = pExpr->pPhrase;
-    int ii;
-    nCost = 0;
-    for(ii=0; ii<pPhrase->nToken; ii++){
-      Fts3SegReaderCursor *pSegcsr = pPhrase->aToken[ii].pSegcsr;
-      if( pSegcsr ) nCost += pSegcsr->nCost;
-    }
-  }else{
-    nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
-  }
-  return nCost;
-}
-
-/*
-** The following is a helper function (and type) for fts3EvalExpr(). It
-** must be called after Fts3SegReaders have been allocated for every token
-** in the expression. See the context it is called from in fts3EvalExpr()
-** for further explanation.
-*/
-typedef struct ExprAndCost ExprAndCost;
-struct ExprAndCost {
-  Fts3Expr *pExpr;
-  int nCost;
-};
-static void fts3ExprAssignCosts(
-  Fts3Expr *pExpr,                /* Expression to create seg-readers for */
-  ExprAndCost **ppExprCost        /* OUT: Write to *ppExprCost */
-){
-  if( pExpr->eType==FTSQUERY_AND ){
-    fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
-    fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
-  }else{
-    (*ppExprCost)->pExpr = pExpr;
-    (*ppExprCost)->nCost = fts3ExprCost(pExpr);
-    (*ppExprCost)++;
-  }
-}
-
-/*
-** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
-** the resulting doclist in *paOut and *pnOut. This routine mallocs for
-** the space needed to store the output. The caller is responsible for
-** freeing the space when it has finished.
-**
-** This function is called in two distinct contexts:
-**
-**   * From within the virtual table xFilter() method. In this case, the
-**     output doclist contains entries for all rows in the table, based on
-**     data read from the full-text index.
-**
-**     In this case, if the query expression contains one or more tokens that 
-**     are very common, then the returned doclist may contain a superset of 
-**     the documents that actually match the expression.
-**
-**   * From within the virtual table xNext() method. This call is only made
-**     if the call from within xFilter() found that there were very common 
-**     tokens in the query expression and did return a superset of the 
-**     matching documents. In this case the returned doclist contains only
-**     entries that correspond to the current row of the table. Instead of
-**     reading the data for each token from the full-text index, the data is
-**     already available in-memory in the Fts3PhraseToken.pDeferred structures.
-**     See fts3EvalDeferred() for how it gets there.
-**
-** In the first case above, Fts3Cursor.doDeferred==0. In the second (if it is
-** required) Fts3Cursor.doDeferred==1.
-**
-** If the SQLite invokes the snippet(), offsets() or matchinfo() function
-** as part of a SELECT on an FTS3 table, this function is called on each
-** individual phrase expression in the query. If there were very common tokens
-** found in the xFilter() call, then this function is called once for phrase
-** for each row visited, and the returned doclist contains entries for the
-** current row only. Otherwise, if there were no very common tokens, then this
-** function is called once only for each phrase in the query and the returned
-** doclist contains entries for all rows of the table.
-**
-** Fts3Cursor.doDeferred==1 when this function is called on phrases as a
-** result of a snippet(), offsets() or matchinfo() invocation.
-*/
-static int fts3EvalExpr(
-  Fts3Cursor *p,                  /* Virtual table cursor handle */
-  Fts3Expr *pExpr,                /* Parsed fts3 expression */
-  char **paOut,                   /* OUT: Pointer to malloc'd result buffer */
-  int *pnOut,                     /* OUT: Size of buffer at *paOut */
-  int isReqPos                    /* Require positions in output buffer */
-){
-  int rc = SQLITE_OK;             /* Return code */
-
-  /* Zero the output parameters. */
-  *paOut = 0;
-  *pnOut = 0;
-
-  if( pExpr ){
-    assert( pExpr->eType==FTSQUERY_NEAR   || pExpr->eType==FTSQUERY_OR     
-         || pExpr->eType==FTSQUERY_AND    || pExpr->eType==FTSQUERY_NOT
-         || pExpr->eType==FTSQUERY_PHRASE
-    );
-    assert( pExpr->eType==FTSQUERY_PHRASE || isReqPos==0 );
-
-    if( pExpr->eType==FTSQUERY_PHRASE ){
-      rc = fts3PhraseSelect(p, pExpr->pPhrase,
-          isReqPos || (pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR),
-          paOut, pnOut
-      );
-      fts3ExprFreeSegReaders(pExpr);
-    }else if( p->eEvalmode==FTS3_EVAL_FILTER && pExpr->eType==FTSQUERY_AND ){
-      ExprAndCost *aExpr = 0;     /* Array of AND'd expressions and costs */
-      int nExpr = 0;              /* Size of aExpr[] */
-      char *aRet = 0;             /* Doclist to return to caller */
-      int nRet = 0;               /* Length of aRet[] in bytes */
-      int nDoc = 0x7FFFFFFF;
-
-      assert( !isReqPos );
-
-      rc = fts3ExprAllocateSegReaders(p, pExpr, &nExpr);
-      if( rc==SQLITE_OK ){
-        assert( nExpr>1 );
-        aExpr = sqlite3_malloc(sizeof(ExprAndCost) * nExpr);
-        if( !aExpr ) rc = SQLITE_NOMEM;
-      }
-      if( rc==SQLITE_OK ){
-        int ii;                   /* Used to iterate through expressions */
-
-        fts3ExprAssignCosts(pExpr, &aExpr);
-        aExpr -= nExpr;
-        for(ii=0; ii<nExpr; ii++){
-          char *aNew;
-          int nNew;
-          int jj;
-          ExprAndCost *pBest = 0;
-  
-          for(jj=0; jj<nExpr; jj++){
-            ExprAndCost *pCand = &aExpr[jj];
-            if( pCand->pExpr && (pBest==0 || pCand->nCost<pBest->nCost) ){
-              pBest = pCand;
-            }
-          }
-  
-          if( pBest->nCost>nDoc ){
-            rc = fts3DeferExpression(p, p->pExpr);
-            break;
-          }else{
-            rc = fts3EvalExpr(p, pBest->pExpr, &aNew, &nNew, 0);
-            if( rc!=SQLITE_OK ) break;
-            pBest->pExpr = 0;
-            if( ii==0 ){
-              aRet = aNew;
-              nRet = nNew;
-              nDoc = fts3DoclistCountDocids(0, aRet, nRet);
-            }else{
-              fts3DoclistMerge(
-                  MERGE_AND, 0, 0, aRet, &nRet, aRet, nRet, aNew, nNew, &nDoc
-              );
-              sqlite3_free(aNew);
-            }
-          }
-        }
-      }
-
-      if( rc==SQLITE_OK ){
-        *paOut = aRet;
-        *pnOut = nRet;
-      }else{
-        assert( *paOut==0 );
-        sqlite3_free(aRet);
-      }
-      sqlite3_free(aExpr);
-      fts3ExprFreeSegReaders(pExpr);
-
-    }else{
-      char *aLeft;
-      char *aRight;
-      int nLeft;
-      int nRight;
-
-      assert( pExpr->eType==FTSQUERY_NEAR 
-           || pExpr->eType==FTSQUERY_OR
-           || pExpr->eType==FTSQUERY_NOT
-           || (pExpr->eType==FTSQUERY_AND && p->eEvalmode==FTS3_EVAL_NEXT)
-      );
-
-      if( 0==(rc = fts3EvalExpr(p, pExpr->pRight, &aRight, &nRight, isReqPos))
-       && 0==(rc = fts3EvalExpr(p, pExpr->pLeft, &aLeft, &nLeft, isReqPos))
-      ){
-        switch( pExpr->eType ){
-          case FTSQUERY_NEAR: {
-            Fts3Expr *pLeft;
-            Fts3Expr *pRight;
-            int mergetype = MERGE_NEAR;
-            if( pExpr->pParent && pExpr->pParent->eType==FTSQUERY_NEAR ){
-              mergetype = MERGE_POS_NEAR;
-            }
-            pLeft = pExpr->pLeft;
-            while( pLeft->eType==FTSQUERY_NEAR ){ 
-              pLeft=pLeft->pRight;
-            }
-            pRight = pExpr->pRight;
-            assert( pRight->eType==FTSQUERY_PHRASE );
-            assert( pLeft->eType==FTSQUERY_PHRASE );
-
-            rc = fts3NearMerge(mergetype, pExpr->nNear, 
-                pLeft->pPhrase->nToken, aLeft, nLeft,
-                pRight->pPhrase->nToken, aRight, nRight,
-                paOut, pnOut
-            );
-            sqlite3_free(aLeft);
-            break;
-          }
-
-          case FTSQUERY_OR: {
-            /* Allocate a buffer for the output. The maximum size is the
-            ** sum of the sizes of the two input buffers. The +1 term is
-            ** so that a buffer of zero bytes is never allocated - this can
-            ** cause fts3DoclistMerge() to incorrectly return SQLITE_NOMEM.
-            */
-            char *aBuffer = sqlite3_malloc(nRight+nLeft+1);
-            rc = fts3DoclistMerge(MERGE_OR, 0, 0, aBuffer, pnOut,
-                aLeft, nLeft, aRight, nRight, 0
-            );
-            *paOut = aBuffer;
-            sqlite3_free(aLeft);
-            break;
-          }
-
-          default: {
-            assert( FTSQUERY_NOT==MERGE_NOT && FTSQUERY_AND==MERGE_AND );
-            fts3DoclistMerge(pExpr->eType, 0, 0, aLeft, pnOut,
-                aLeft, nLeft, aRight, nRight, 0
-            );
-            *paOut = aLeft;
-            break;
-          }
-        }
-      }
-      sqlite3_free(aRight);
-    }
-  }
-
-  assert( rc==SQLITE_OK || *paOut==0 );
-  return rc;
-}
-
-/*
-** This function is called from within xNext() for each row visited by
-** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
-** was able to determine the exact set of matching rows, this function sets
-** *pbRes to true and returns SQLITE_IO immediately.
-**
-** Otherwise, if evaluating the query expression within xFilter() returned a
-** superset of the matching documents instead of an exact set (this happens
-** when the query includes very common tokens and it is deemed too expensive to
-** load their doclists from disk), this function tests if the current row
-** really does match the FTS3 query.
-**
-** If an error occurs, an SQLite error code is returned. Otherwise, SQLITE_OK
-** is returned and *pbRes is set to true if the current row matches the
-** FTS3 query (and should be included in the results returned to SQLite), or
-** false otherwise.
-*/
-static int fts3EvalDeferred(
-  Fts3Cursor *pCsr,               /* FTS3 cursor pointing at row to test */
-  int *pbRes                      /* OUT: Set to true if row is a match */
-){
-  int rc = SQLITE_OK;
-  if( pCsr->pDeferred==0 ){
-    *pbRes = 1;
-  }else{
-    rc = fts3CursorSeek(0, pCsr);
-    if( rc==SQLITE_OK ){
-      sqlite3Fts3FreeDeferredDoclists(pCsr);
-      rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
-    }
-    if( rc==SQLITE_OK ){
-      char *a = 0;
-      int n = 0;
-      rc = fts3EvalExpr(pCsr, pCsr->pExpr, &a, &n, 0);
-      assert( n>=0 );
-      *pbRes = (n>0);
-      sqlite3_free(a);
-    }
-  }
-  return rc;
-}
-
 /*
 ** Advance the cursor to the next row in the %_content table that
 ** matches the search criteria.  For a MATCH search, this will be
@@ -113752,31 +114456,20 @@ static int fts3EvalDeferred(
 ** subsequently to determine whether or not an EOF was hit.
 */
 static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
-  int res;
-  int rc = SQLITE_OK;             /* Return code */
+  int rc;
   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
-
-  pCsr->eEvalmode = FTS3_EVAL_NEXT;
-  do {
-    if( pCsr->aDoclist==0 ){
-      if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
-        pCsr->isEof = 1;
-        rc = sqlite3_reset(pCsr->pStmt);
-        break;
-      }
-      pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
+  if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
+    if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
+      pCsr->isEof = 1;
+      rc = sqlite3_reset(pCsr->pStmt);
     }else{
-      if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){
-        pCsr->isEof = 1;
-        break;
-      }
-      sqlite3_reset(pCsr->pStmt);
-      fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId);
-      pCsr->isRequireSeek = 1;
-      pCsr->isMatchinfoNeeded = 1;
+      pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
+      rc = SQLITE_OK;
     }
-  }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 );
-
+  }else{
+    rc = sqlite3Fts3EvalNext((Fts3Cursor *)pCursor);
+  }
+  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
   return rc;
 }
 
@@ -113803,11 +114496,7 @@ static int fts3FilterMethod(
   int nVal,                       /* Number of elements in apVal */
   sqlite3_value **apVal           /* Arguments for the indexing scheme */
 ){
-  const char *azSql[] = {
-    "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */
-    "SELECT %s FROM %Q.'%q_content' AS x ",                /* full-scan */
-  };
-  int rc;                         /* Return code */
+  int rc;
   char *zSql;                     /* SQL statement used to access %_content */
   Fts3Table *p = (Fts3Table *)pCursor->pVtab;
   Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
@@ -113826,6 +114515,13 @@ static int fts3FilterMethod(
   sqlite3Fts3ExprFree(pCsr->pExpr);
   memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
 
+  if( idxStr ){
+    pCsr->bDesc = (idxStr[0]=='D');
+  }else{
+    pCsr->bDesc = p->bDescIdx;
+  }
+  pCsr->eSearch = (i16)idxNum;
+
   if( idxNum!=FTS3_DOCID_SEARCH && idxNum!=FTS3_FULLSCAN_SEARCH ){
     int iCol = idxNum-FTS3_FULLTEXT_SEARCH;
     const char *zQuery = (const char *)sqlite3_value_text(apVal[0]);
@@ -113839,8 +114535,8 @@ static int fts3FilterMethod(
     );
     if( rc!=SQLITE_OK ){
       if( rc==SQLITE_ERROR ){
-        p->base.zErrMsg = sqlite3_mprintf("malformed MATCH expression: [%s]",
-                                          zQuery);
+        static const char *zErr = "malformed MATCH expression: [%s]";
+        p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
       }
       return rc;
     }
@@ -113848,7 +114544,8 @@ static int fts3FilterMethod(
     rc = sqlite3Fts3ReadLock(p);
     if( rc!=SQLITE_OK ) return rc;
 
-    rc = fts3EvalExpr(pCsr, pCsr->pExpr, &pCsr->aDoclist, &pCsr->nDoclist, 0);
+    rc = sqlite3Fts3EvalStart(pCsr, pCsr->pExpr, 1);
+
     sqlite3Fts3SegmentsClose(p);
     if( rc!=SQLITE_OK ) return rc;
     pCsr->pNextId = pCsr->aDoclist;
@@ -113860,20 +114557,24 @@ static int fts3FilterMethod(
   ** full-text query or docid lookup, the statement retrieves a single
   ** row by docid.
   */
-  zSql = (char *)azSql[idxNum==FTS3_FULLSCAN_SEARCH];
-  zSql = sqlite3_mprintf(zSql, p->zReadExprlist, p->zDb, p->zName);
-  if( !zSql ){
-    rc = SQLITE_NOMEM;
+  if( idxNum==FTS3_FULLSCAN_SEARCH ){
+    const char *zSort = (pCsr->bDesc ? "DESC" : "ASC");
+    const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s";
+    zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort);
   }else{
-    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
-    sqlite3_free(zSql);
+    const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?";
+    zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName);
   }
-  if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){
+  if( !zSql ) return SQLITE_NOMEM;
+  rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
+  sqlite3_free(zSql);
+  if( rc!=SQLITE_OK ) return rc;
+
+  if( idxNum==FTS3_DOCID_SEARCH ){
     rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
+    if( rc!=SQLITE_OK ) return rc;
   }
-  pCsr->eSearch = (i16)idxNum;
 
-  if( rc!=SQLITE_OK ) return rc;
   return fts3NextMethod(pCursor);
 }
 
@@ -113893,16 +114594,7 @@ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
 */
 static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
   Fts3Cursor *pCsr = (Fts3Cursor *) pCursor;
-  if( pCsr->aDoclist ){
-    *pRowid = pCsr->iPrevId;
-  }else{
-    /* This branch runs if the query is implemented using a full-table scan
-    ** (not using the full-text index). In this case grab the rowid from the
-    ** SELECT statement.
-    */
-    assert( pCsr->isRequireSeek==0 );
-    *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
-  }
+  *pRowid = pCsr->iPrevId;
   return SQLITE_OK;
 }
 
@@ -113915,7 +114607,7 @@ static int fts3ColumnMethod(
   sqlite3_context *pContext,      /* Context for sqlite3_result_xxx() calls */
   int iCol                        /* Index of column to read value from */
 ){
-  int rc;                         /* Return Code */
+  int rc = SQLITE_OK;             /* Return Code */
   Fts3Cursor *pCsr = (Fts3Cursor *) pCursor;
   Fts3Table *p = (Fts3Table *)pCursor->pVtab;
 
@@ -113926,21 +114618,20 @@ static int fts3ColumnMethod(
     /* This call is a request for the "docid" column. Since "docid" is an 
     ** alias for "rowid", use the xRowid() method to obtain the value.
     */
-    sqlite3_int64 iRowid;
-    rc = fts3RowidMethod(pCursor, &iRowid);
-    sqlite3_result_int64(pContext, iRowid);
+    sqlite3_result_int64(pContext, pCsr->iPrevId);
   }else if( iCol==p->nColumn ){
     /* The extra column whose name is the same as the table.
     ** Return a blob which is a pointer to the cursor.
     */
     sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
-    rc = SQLITE_OK;
   }else{
     rc = fts3CursorSeek(0, pCsr);
     if( rc==SQLITE_OK ){
       sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
     }
   }
+
+  assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
   return rc;
 }
 
@@ -113972,8 +114663,13 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
 ** Implementation of xBegin() method. This is a no-op.
 */
 static int fts3BeginMethod(sqlite3_vtab *pVtab){
+  TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
   UNUSED_PARAMETER(pVtab);
-  assert( ((Fts3Table *)pVtab)->nPendingData==0 );
+  assert( p->pSegments==0 );
+  assert( p->nPendingData==0 );
+  assert( p->inTransaction!=1 );
+  TESTONLY( p->inTransaction = 1 );
+  TESTONLY( p->mxSavepoint = -1; );
   return SQLITE_OK;
 }
 
@@ -113983,8 +114679,13 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){
 ** by fts3SyncMethod().
 */
 static int fts3CommitMethod(sqlite3_vtab *pVtab){
+  TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
   UNUSED_PARAMETER(pVtab);
-  assert( ((Fts3Table *)pVtab)->nPendingData==0 );
+  assert( p->nPendingData==0 );
+  assert( p->inTransaction!=0 );
+  assert( p->pSegments==0 );
+  TESTONLY( p->inTransaction = 0 );
+  TESTONLY( p->mxSavepoint = -1; );
   return SQLITE_OK;
 }
 
@@ -113993,93 +114694,31 @@ static int fts3CommitMethod(sqlite3_vtab *pVtab){
 ** hash-table. Any changes made to the database are reverted by SQLite.
 */
 static int fts3RollbackMethod(sqlite3_vtab *pVtab){
-  sqlite3Fts3PendingTermsClear((Fts3Table *)pVtab);
+  Fts3Table *p = (Fts3Table*)pVtab;
+  sqlite3Fts3PendingTermsClear(p);
+  assert( p->inTransaction!=0 );
+  TESTONLY( p->inTransaction = 0 );
+  TESTONLY( p->mxSavepoint = -1; );
   return SQLITE_OK;
 }
 
 /*
-** Load the doclist associated with expression pExpr to pExpr->aDoclist.
-** The loaded doclist contains positions as well as the document ids.
-** This is used by the matchinfo(), snippet() and offsets() auxillary
-** functions.
+** When called, *ppPoslist must point to the byte immediately following the
+** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function
+** moves *ppPoslist so that it instead points to the first byte of the
+** same position list.
 */
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *pCsr, Fts3Expr *pExpr){
-  int rc;
-  assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
-  assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
-  rc = fts3EvalExpr(pCsr, pExpr, &pExpr->aDoclist, &pExpr->nDoclist, 1);
-  return rc;
-}
+static void fts3ReversePoslist(char *pStart, char **ppPoslist){
+  char *p = &(*ppPoslist)[-2];
+  char c;
 
-SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(
-  Fts3Cursor *pCsr, 
-  Fts3Expr *pExpr,
-  char **paDoclist,
-  int *pnDoclist
-){
-  int rc;
-  assert( pCsr->eEvalmode==FTS3_EVAL_NEXT );
-  assert( pExpr->eType==FTSQUERY_PHRASE && pExpr->pPhrase );
-  pCsr->eEvalmode = FTS3_EVAL_MATCHINFO;
-  rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1);
-  pCsr->eEvalmode = FTS3_EVAL_NEXT;
-  return rc;
-}
-
-/*
-** After ExprLoadDoclist() (see above) has been called, this function is
-** used to iterate/search through the position lists that make up the doclist
-** stored in pExpr->aDoclist.
-*/
-SQLITE_PRIVATE char *sqlite3Fts3FindPositions(
-  Fts3Expr *pExpr,                /* Access this expressions doclist */
-  sqlite3_int64 iDocid,           /* Docid associated with requested pos-list */
-  int iCol                        /* Column of requested pos-list */
-){
-  assert( pExpr->isLoaded );
-  if( pExpr->aDoclist ){
-    char *pEnd = &pExpr->aDoclist[pExpr->nDoclist];
-    char *pCsr;
-
-    if( pExpr->pCurrent==0 ){
-      pExpr->pCurrent = pExpr->aDoclist;
-      pExpr->iCurrent = 0;
-      pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent);
-    }
-    pCsr = pExpr->pCurrent;
-    assert( pCsr );
-
-    while( pCsr<pEnd ){
-      if( pExpr->iCurrent<iDocid ){
-        fts3PoslistCopy(0, &pCsr);
-        if( pCsr<pEnd ){
-          fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent);
-        }
-        pExpr->pCurrent = pCsr;
-      }else{
-        if( pExpr->iCurrent==iDocid ){
-          int iThis = 0;
-          if( iCol<0 ){
-            /* If iCol is negative, return a pointer to the start of the
-            ** position-list (instead of a pointer to the start of a list
-            ** of offsets associated with a specific column).
-            */
-            return pCsr;
-          }
-          while( iThis<iCol ){
-            fts3ColumnlistCopy(0, &pCsr);
-            if( *pCsr==0x00 ) return 0;
-            pCsr++;
-            pCsr += sqlite3Fts3GetVarint32(pCsr, &iThis);
-          }
-          if( iCol==iThis && (*pCsr&0xFE) ) return pCsr;
-        }
-        return 0;
-      }
-    }
+  while( p>pStart && (c=*p--)==0 );
+  while( p>pStart && (*p & 0x80) | c ){ 
+    c = *p--; 
   }
-
-  return 0;
+  if( p>pStart ){ p = &p[2]; }
+  while( *p++&0x80 );
+  *ppPoslist = p;
 }
 
 /*
@@ -114312,8 +114951,34 @@ static int fts3RenameMethod(
   return rc;
 }
 
+static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  UNUSED_PARAMETER(iSavepoint);
+  assert( ((Fts3Table *)pVtab)->inTransaction );
+  assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
+  TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
+  return fts3SyncMethod(pVtab);
+}
+static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
+  UNUSED_PARAMETER(iSavepoint);
+  UNUSED_PARAMETER(pVtab);
+  assert( p->inTransaction );
+  assert( p->mxSavepoint >= iSavepoint );
+  TESTONLY( p->mxSavepoint = iSavepoint-1 );
+  return SQLITE_OK;
+}
+static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  Fts3Table *p = (Fts3Table*)pVtab;
+  UNUSED_PARAMETER(iSavepoint);
+  assert( p->inTransaction );
+  assert( p->mxSavepoint >= iSavepoint );
+  TESTONLY( p->mxSavepoint = iSavepoint );
+  sqlite3Fts3PendingTermsClear(p);
+  return SQLITE_OK;
+}
+
 static const sqlite3_module fts3Module = {
-  /* iVersion      */ 0,
+  /* iVersion      */ 2,
   /* xCreate       */ fts3CreateMethod,
   /* xConnect      */ fts3ConnectMethod,
   /* xBestIndex    */ fts3BestIndexMethod,
@@ -114333,6 +114998,9 @@ static const sqlite3_module fts3Module = {
   /* xRollback     */ fts3RollbackMethod,
   /* xFindFunction */ fts3FindFunctionMethod,
   /* xRename */       fts3RenameMethod,
+  /* xSavepoint    */ fts3SavepointMethod,
+  /* xRelease      */ fts3ReleaseMethod,
+  /* xRollbackTo   */ fts3RollbackToMethod,
 };
 
 /*
@@ -114379,6 +115047,11 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
   sqlite3Fts3IcuTokenizerModule(&pIcu);
 #endif
 
+#ifdef SQLITE_TEST
+  rc = sqlite3Fts3InitTerm(db);
+  if( rc!=SQLITE_OK ) return rc;
+#endif
+
   rc = sqlite3Fts3InitAux(db);
   if( rc!=SQLITE_OK ) return rc;
 
@@ -114454,6 +115127,1308 @@ SQLITE_API int sqlite3_extension_init(
 }
 #endif
 
+
+/*
+** Allocate an Fts3MultiSegReader for each token in the expression headed
+** by pExpr. 
+**
+** An Fts3SegReader object is a cursor that can seek or scan a range of
+** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple
+** Fts3SegReader objects internally to provide an interface to seek or scan
+** within the union of all segments of a b-tree. Hence the name.
+**
+** If the allocated Fts3MultiSegReader just seeks to a single entry in a
+** segment b-tree (if the term is not a prefix or it is a prefix for which
+** there exists prefix b-tree of the right length) then it may be traversed
+** and merged incrementally. Otherwise, it has to be merged into an in-memory 
+** doclist and then traversed.
+*/
+static void fts3EvalAllocateReaders(
+  Fts3Cursor *pCsr, 
+  Fts3Expr *pExpr, 
+  int *pnToken,                   /* OUT: Total number of tokens in phrase. */
+  int *pnOr,                      /* OUT: Total number of OR nodes in expr. */
+  int *pRc
+){
+  if( pExpr && SQLITE_OK==*pRc ){
+    if( pExpr->eType==FTSQUERY_PHRASE ){
+      int i;
+      int nToken = pExpr->pPhrase->nToken;
+      *pnToken += nToken;
+      for(i=0; i<nToken; i++){
+        Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
+        int rc = sqlite3Fts3TermSegReaderCursor(pCsr, 
+            pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr
+        );
+        if( rc!=SQLITE_OK ){
+          *pRc = rc;
+          return;
+        }
+      }
+      assert( pExpr->pPhrase->iDoclistToken==0 );
+      pExpr->pPhrase->iDoclistToken = -1;
+    }else{
+      *pnOr += (pExpr->eType==FTSQUERY_OR);
+      fts3EvalAllocateReaders(pCsr, pExpr->pLeft, pnToken, pnOr, pRc);
+      fts3EvalAllocateReaders(pCsr, pExpr->pRight, pnToken, pnOr, pRc);
+    }
+  }
+}
+
+static void fts3EvalPhraseMergeToken(
+  Fts3Table *pTab,
+  Fts3Phrase *p,
+  int iToken,
+  char *pList,
+  int nList
+){
+  assert( iToken!=p->iDoclistToken );
+
+  if( pList==0 ){
+    sqlite3_free(p->doclist.aAll);
+    p->doclist.aAll = 0;
+    p->doclist.nAll = 0;
+  }
+
+  else if( p->iDoclistToken<0 ){
+    p->doclist.aAll = pList;
+    p->doclist.nAll = nList;
+  }
+
+  else if( p->doclist.aAll==0 ){
+    sqlite3_free(pList);
+  }
+
+  else {
+    char *pLeft;
+    char *pRight;
+    int nLeft;
+    int nRight;
+    int nDiff;
+
+    if( p->iDoclistToken<iToken ){
+      pLeft = p->doclist.aAll;
+      nLeft = p->doclist.nAll;
+      pRight = pList;
+      nRight = nList;
+      nDiff = iToken - p->iDoclistToken;
+    }else{
+      pRight = p->doclist.aAll;
+      nRight = p->doclist.nAll;
+      pLeft = pList;
+      nLeft = nList;
+      nDiff = p->iDoclistToken - iToken;
+    }
+
+    fts3DoclistPhraseMerge(pTab->bDescIdx, nDiff, pLeft, nLeft, pRight,&nRight);
+    sqlite3_free(pLeft);
+    p->doclist.aAll = pRight;
+    p->doclist.nAll = nRight;
+  }
+
+  if( iToken>p->iDoclistToken ) p->iDoclistToken = iToken;
+}
+
+static int fts3EvalPhraseLoad(
+  Fts3Cursor *pCsr, 
+  Fts3Phrase *p
+){
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  int iToken;
+  int rc = SQLITE_OK;
+
+  for(iToken=0; rc==SQLITE_OK && iToken<p->nToken; iToken++){
+    Fts3PhraseToken *pToken = &p->aToken[iToken];
+    assert( pToken->pDeferred==0 || pToken->pSegcsr==0 );
+
+    if( pToken->pSegcsr ){
+      int nThis = 0;
+      char *pThis = 0;
+      rc = fts3TermSelect(pTab, pToken, p->iColumn, 1, &nThis, &pThis);
+      if( rc==SQLITE_OK ){
+        fts3EvalPhraseMergeToken(pTab, p, iToken, pThis, nThis);
+      }
+    }
+    assert( pToken->pSegcsr==0 );
+  }
+
+  return rc;
+}
+
+static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
+  int iToken;
+  int rc = SQLITE_OK;
+
+  int nMaxUndeferred = pPhrase->iDoclistToken;
+  char *aPoslist = 0;
+  int nPoslist = 0;
+  int iPrev = -1;
+
+  assert( pPhrase->doclist.bFreeList==0 );
+
+  for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){
+    Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
+    Fts3DeferredToken *pDeferred = pToken->pDeferred;
+
+    if( pDeferred ){
+      char *pList;
+      int nList;
+      rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
+      if( rc!=SQLITE_OK ) return rc;
+
+      if( pList==0 ){
+        sqlite3_free(aPoslist);
+        pPhrase->doclist.pList = 0;
+        pPhrase->doclist.nList = 0;
+        return SQLITE_OK;
+
+      }else if( aPoslist==0 ){
+        aPoslist = pList;
+        nPoslist = nList;
+
+      }else{
+        char *aOut = pList;
+        char *p1 = aPoslist;
+        char *p2 = aOut;
+
+        assert( iPrev>=0 );
+        fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2);
+        sqlite3_free(aPoslist);
+        aPoslist = pList;
+        nPoslist = aOut - aPoslist;
+        if( nPoslist==0 ){
+          sqlite3_free(aPoslist);
+          pPhrase->doclist.pList = 0;
+          pPhrase->doclist.nList = 0;
+          return SQLITE_OK;
+        }
+      }
+      iPrev = iToken;
+    }
+  }
+
+  if( iPrev>=0 ){
+    if( nMaxUndeferred<0 ){
+      pPhrase->doclist.pList = aPoslist;
+      pPhrase->doclist.nList = nPoslist;
+      pPhrase->doclist.iDocid = pCsr->iPrevId;
+      pPhrase->doclist.bFreeList = 1;
+    }else{
+      int nDistance;
+      char *p1;
+      char *p2;
+      char *aOut;
+
+      if( nMaxUndeferred>iPrev ){
+        p1 = aPoslist;
+        p2 = pPhrase->doclist.pList;
+        nDistance = nMaxUndeferred - iPrev;
+      }else{
+        p1 = pPhrase->doclist.pList;
+        p2 = aPoslist;
+        nDistance = iPrev - nMaxUndeferred;
+      }
+
+      aOut = (char *)sqlite3_malloc(nPoslist+8);
+      if( !aOut ){
+        sqlite3_free(aPoslist);
+        return SQLITE_NOMEM;
+      }
+      
+      pPhrase->doclist.pList = aOut;
+      if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
+        pPhrase->doclist.bFreeList = 1;
+        pPhrase->doclist.nList = (aOut - pPhrase->doclist.pList);
+      }else{
+        sqlite3_free(aOut);
+        pPhrase->doclist.pList = 0;
+        pPhrase->doclist.nList = 0;
+      }
+      sqlite3_free(aPoslist);
+    }
+  }
+
+  return SQLITE_OK;
+}
+
+/*
+** This function is called for each Fts3Phrase in a full-text query 
+** expression to initialize the mechanism for returning rows. Once this
+** function has been called successfully on an Fts3Phrase, it may be
+** used with fts3EvalPhraseNext() to iterate through the matching docids.
+*/
+static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
+  int rc;
+  Fts3PhraseToken *pFirst = &p->aToken[0];
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+
+  if( pCsr->bDesc==pTab->bDescIdx 
+   && bOptOk==1 
+   && p->nToken==1 
+   && pFirst->pSegcsr 
+   && pFirst->pSegcsr->bLookup 
+  ){
+    /* Use the incremental approach. */
+    int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
+    rc = sqlite3Fts3MsrIncrStart(
+        pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
+    p->bIncr = 1;
+
+  }else{
+    /* Load the full doclist for the phrase into memory. */
+    rc = fts3EvalPhraseLoad(pCsr, p);
+    p->bIncr = 0;
+  }
+
+  assert( rc!=SQLITE_OK || p->nToken<1 || p->aToken[0].pSegcsr==0 || p->bIncr );
+  return rc;
+}
+
+/*
+** This function is used to iterate backwards (from the end to start) 
+** through doclists.
+*/
+SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(
+  int bDescIdx,                   /* True if the doclist is desc */
+  char *aDoclist,                 /* Pointer to entire doclist */
+  int nDoclist,                   /* Length of aDoclist in bytes */
+  char **ppIter,                  /* IN/OUT: Iterator pointer */
+  sqlite3_int64 *piDocid,         /* IN/OUT: Docid pointer */
+  int *pnList,                    /* IN/OUT: List length pointer */
+  u8 *pbEof                       /* OUT: End-of-file flag */
+){
+  char *p = *ppIter;
+
+  assert( nDoclist>0 );
+  assert( *pbEof==0 );
+  assert( p || *piDocid==0 );
+  assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) );
+
+  if( p==0 ){
+    sqlite3_int64 iDocid = 0;
+    char *pNext = 0;
+    char *pDocid = aDoclist;
+    char *pEnd = &aDoclist[nDoclist];
+    int iMul = 1;
+
+    while( pDocid<pEnd ){
+      sqlite3_int64 iDelta;
+      pDocid += sqlite3Fts3GetVarint(pDocid, &iDelta);
+      iDocid += (iMul * iDelta);
+      pNext = pDocid;
+      fts3PoslistCopy(0, &pDocid);
+      while( pDocid<pEnd && *pDocid==0 ) pDocid++;
+      iMul = (bDescIdx ? -1 : 1);
+    }
+
+    *pnList = pEnd - pNext;
+    *ppIter = pNext;
+    *piDocid = iDocid;
+  }else{
+    int iMul = (bDescIdx ? -1 : 1);
+    sqlite3_int64 iDelta;
+    fts3GetReverseVarint(&p, aDoclist, &iDelta);
+    *piDocid -= (iMul * iDelta);
+
+    if( p==aDoclist ){
+      *pbEof = 1;
+    }else{
+      char *pSave = p;
+      fts3ReversePoslist(aDoclist, &p);
+      *pnList = (pSave - p);
+    }
+    *ppIter = p;
+  }
+}
+
+/*
+** Attempt to move the phrase iterator to point to the next matching docid. 
+** If an error occurs, return an SQLite error code. Otherwise, return 
+** SQLITE_OK.
+**
+** If there is no "next" entry and no error occurs, then *pbEof is set to
+** 1 before returning. Otherwise, if no error occurs and the iterator is
+** successfully advanced, *pbEof is set to 0.
+*/
+static int fts3EvalPhraseNext(
+  Fts3Cursor *pCsr, 
+  Fts3Phrase *p, 
+  u8 *pbEof
+){
+  int rc = SQLITE_OK;
+  Fts3Doclist *pDL = &p->doclist;
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+
+  if( p->bIncr ){
+    assert( p->nToken==1 );
+    assert( pDL->pNextDocid==0 );
+    rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr, 
+        &pDL->iDocid, &pDL->pList, &pDL->nList
+    );
+    if( rc==SQLITE_OK && !pDL->pList ){
+      *pbEof = 1;
+    }
+  }else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
+    sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll, 
+        &pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
+    );
+    pDL->pList = pDL->pNextDocid;
+  }else{
+    char *pIter;                            /* Used to iterate through aAll */
+    char *pEnd = &pDL->aAll[pDL->nAll];     /* 1 byte past end of aAll */
+    if( pDL->pNextDocid ){
+      pIter = pDL->pNextDocid;
+    }else{
+      pIter = pDL->aAll;
+    }
+
+    if( pIter>=pEnd ){
+      /* We have already reached the end of this doclist. EOF. */
+      *pbEof = 1;
+    }else{
+      sqlite3_int64 iDelta;
+      pIter += sqlite3Fts3GetVarint(pIter, &iDelta);
+      if( pTab->bDescIdx==0 || pDL->pNextDocid==0 ){
+        pDL->iDocid += iDelta;
+      }else{
+        pDL->iDocid -= iDelta;
+      }
+      pDL->pList = pIter;
+      fts3PoslistCopy(0, &pIter);
+      pDL->nList = (pIter - pDL->pList);
+
+      /* pIter now points just past the 0x00 that terminates the position-
+      ** list for document pDL->iDocid. However, if this position-list was
+      ** edited in place by fts3EvalNearTrim2(), then pIter may not actually
+      ** point to the start of the next docid value. The following line deals
+      ** with this case by advancing pIter past the zero-padding added by
+      ** fts3EvalNearTrim2().  */
+      while( pIter<pEnd && *pIter==0 ) pIter++;
+
+      pDL->pNextDocid = pIter;
+      assert( pIter>=&pDL->aAll[pDL->nAll] || *pIter );
+      *pbEof = 0;
+    }
+  }
+
+  return rc;
+}
+
+static void fts3EvalStartReaders(
+  Fts3Cursor *pCsr, 
+  Fts3Expr *pExpr, 
+  int bOptOk,
+  int *pRc
+){
+  if( pExpr && SQLITE_OK==*pRc ){
+    if( pExpr->eType==FTSQUERY_PHRASE ){
+      int i;
+      int nToken = pExpr->pPhrase->nToken;
+      for(i=0; i<nToken; i++){
+        if( pExpr->pPhrase->aToken[i].pDeferred==0 ) break;
+      }
+      pExpr->bDeferred = (i==nToken);
+      *pRc = fts3EvalPhraseStart(pCsr, bOptOk, pExpr->pPhrase);
+    }else{
+      fts3EvalStartReaders(pCsr, pExpr->pLeft, bOptOk, pRc);
+      fts3EvalStartReaders(pCsr, pExpr->pRight, bOptOk, pRc);
+      pExpr->bDeferred = (pExpr->pLeft->bDeferred && pExpr->pRight->bDeferred);
+    }
+  }
+}
+
+typedef struct Fts3TokenAndCost Fts3TokenAndCost;
+struct Fts3TokenAndCost {
+  Fts3Phrase *pPhrase;            /* The phrase the token belongs to */
+  int iToken;                     /* Position of token in phrase */
+  Fts3PhraseToken *pToken;        /* The token itself */
+  Fts3Expr *pRoot; 
+  int nOvfl;
+  int iCol;                       /* The column the token must match */
+};
+
+static void fts3EvalTokenCosts(
+  Fts3Cursor *pCsr, 
+  Fts3Expr *pRoot, 
+  Fts3Expr *pExpr, 
+  Fts3TokenAndCost **ppTC,
+  Fts3Expr ***ppOr,
+  int *pRc
+){
+  if( *pRc==SQLITE_OK && pExpr ){
+    if( pExpr->eType==FTSQUERY_PHRASE ){
+      Fts3Phrase *pPhrase = pExpr->pPhrase;
+      int i;
+      for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){
+        Fts3TokenAndCost *pTC = (*ppTC)++;
+        pTC->pPhrase = pPhrase;
+        pTC->iToken = i;
+        pTC->pRoot = pRoot;
+        pTC->pToken = &pPhrase->aToken[i];
+        pTC->iCol = pPhrase->iColumn;
+        *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
+      }
+    }else if( pExpr->eType!=FTSQUERY_NOT ){
+      if( pExpr->eType==FTSQUERY_OR ){
+        pRoot = pExpr->pLeft;
+        **ppOr = pRoot;
+        (*ppOr)++;
+      }
+      fts3EvalTokenCosts(pCsr, pRoot, pExpr->pLeft, ppTC, ppOr, pRc);
+      if( pExpr->eType==FTSQUERY_OR ){
+        pRoot = pExpr->pRight;
+        **ppOr = pRoot;
+        (*ppOr)++;
+      }
+      fts3EvalTokenCosts(pCsr, pRoot, pExpr->pRight, ppTC, ppOr, pRc);
+    }
+  }
+}
+
+static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
+  if( pCsr->nRowAvg==0 ){
+    /* The average document size, which is required to calculate the cost
+     ** of each doclist, has not yet been determined. Read the required 
+     ** data from the %_stat table to calculate it.
+     **
+     ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 
+     ** varints, where nCol is the number of columns in the FTS3 table.
+     ** The first varint is the number of documents currently stored in
+     ** the table. The following nCol varints contain the total amount of
+     ** data stored in all rows of each column of the table, from left
+     ** to right.
+     */
+    int rc;
+    Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
+    sqlite3_stmt *pStmt;
+    sqlite3_int64 nDoc = 0;
+    sqlite3_int64 nByte = 0;
+    const char *pEnd;
+    const char *a;
+
+    rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
+    if( rc!=SQLITE_OK ) return rc;
+    a = sqlite3_column_blob(pStmt, 0);
+    assert( a );
+
+    pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
+    a += sqlite3Fts3GetVarint(a, &nDoc);
+    while( a<pEnd ){
+      a += sqlite3Fts3GetVarint(a, &nByte);
+    }
+    if( nDoc==0 || nByte==0 ){
+      sqlite3_reset(pStmt);
+      return SQLITE_CORRUPT_VTAB;
+    }
+
+    pCsr->nDoc = nDoc;
+    pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
+    assert( pCsr->nRowAvg>0 ); 
+    rc = sqlite3_reset(pStmt);
+    if( rc!=SQLITE_OK ) return rc;
+  }
+
+  *pnPage = pCsr->nRowAvg;
+  return SQLITE_OK;
+}
+
+static int fts3EvalSelectDeferred(
+  Fts3Cursor *pCsr,
+  Fts3Expr *pRoot,
+  Fts3TokenAndCost *aTC,
+  int nTC
+){
+  int nDocSize = 0;
+  int nDocEst = 0;
+  int rc = SQLITE_OK;
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  int ii;
+
+  int nOvfl = 0;
+  int nTerm = 0;
+
+  for(ii=0; ii<nTC; ii++){
+    if( aTC[ii].pRoot==pRoot ){
+      nOvfl += aTC[ii].nOvfl;
+      nTerm++;
+    }
+  }
+  if( nOvfl==0 || nTerm<2 ) return SQLITE_OK;
+
+  rc = fts3EvalAverageDocsize(pCsr, &nDocSize);
+
+  for(ii=0; ii<nTerm && rc==SQLITE_OK; ii++){
+    int jj;
+    Fts3TokenAndCost *pTC = 0;
+
+    for(jj=0; jj<nTC; jj++){
+      if( aTC[jj].pToken && aTC[jj].pRoot==pRoot 
+       && (!pTC || aTC[jj].nOvfl<pTC->nOvfl) 
+      ){
+        pTC = &aTC[jj];
+      }
+    }
+    assert( pTC );
+
+    /* At this point pTC points to the cheapest remaining token. */
+    if( ii==0 ){
+      if( pTC->nOvfl ){
+        nDocEst = (pTC->nOvfl * pTab->nPgsz + pTab->nPgsz) / 10;
+      }else{
+        Fts3PhraseToken *pToken = pTC->pToken;
+        int nList = 0;
+        char *pList = 0;
+        rc = fts3TermSelect(pTab, pToken, pTC->iCol, 1, &nList, &pList);
+        assert( rc==SQLITE_OK || pList==0 );
+
+        if( rc==SQLITE_OK ){
+          nDocEst = fts3DoclistCountDocids(1, pList, nList);
+          fts3EvalPhraseMergeToken(pTab, pTC->pPhrase, pTC->iToken,pList,nList);
+        }
+      }
+    }else{
+      if( pTC->nOvfl>=(nDocEst*nDocSize) ){
+        Fts3PhraseToken *pToken = pTC->pToken;
+        rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol);
+        fts3SegReaderCursorFree(pToken->pSegcsr);
+        pToken->pSegcsr = 0;
+      }
+      nDocEst = 1 + (nDocEst/4);
+    }
+    pTC->pToken = 0;
+  }
+
+  return rc;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3EvalStart(Fts3Cursor *pCsr, Fts3Expr *pExpr, int bOptOk){
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  int rc = SQLITE_OK;
+  int nToken = 0;
+  int nOr = 0;
+
+  /* Allocate a MultiSegReader for each token in the expression. */
+  fts3EvalAllocateReaders(pCsr, pExpr, &nToken, &nOr, &rc);
+
+  /* Call fts3EvalPhraseStart() on all phrases in the expression. TODO:
+  ** This call will eventually also be responsible for determining which
+  ** tokens are 'deferred' until the document text is loaded into memory.
+  **
+  ** Each token in each phrase is dealt with using one of the following
+  ** three strategies:
+  **
+  **   1. Entire doclist loaded into memory as part of the
+  **      fts3EvalStartReaders() call.
+  **
+  **   2. Doclist loaded into memory incrementally, as part of each
+  **      sqlite3Fts3EvalNext() call.
+  **
+  **   3. Token doclist is never loaded. Instead, documents are loaded into
+  **      memory and scanned for the token as part of the sqlite3Fts3EvalNext()
+  **      call. This is known as a "deferred" token.
+  */
+
+  /* If bOptOk is true, check if there are any tokens that should be deferred.
+  */
+  if( rc==SQLITE_OK && bOptOk && nToken>1 && pTab->bHasStat ){
+    Fts3TokenAndCost *aTC;
+    Fts3Expr **apOr;
+    aTC = (Fts3TokenAndCost *)sqlite3_malloc(
+        sizeof(Fts3TokenAndCost) * nToken
+      + sizeof(Fts3Expr *) * nOr * 2
+    );
+    apOr = (Fts3Expr **)&aTC[nToken];
+
+    if( !aTC ){
+      rc = SQLITE_NOMEM;
+    }else{
+      int ii;
+      Fts3TokenAndCost *pTC = aTC;
+      Fts3Expr **ppOr = apOr;
+
+      fts3EvalTokenCosts(pCsr, 0, pExpr, &pTC, &ppOr, &rc);
+      nToken = pTC-aTC;
+      nOr = ppOr-apOr;
+
+      if( rc==SQLITE_OK ){
+        rc = fts3EvalSelectDeferred(pCsr, 0, aTC, nToken);
+        for(ii=0; rc==SQLITE_OK && ii<nOr; ii++){
+          rc = fts3EvalSelectDeferred(pCsr, apOr[ii], aTC, nToken);
+        }
+      }
+
+      sqlite3_free(aTC);
+    }
+  }
+
+  fts3EvalStartReaders(pCsr, pExpr, bOptOk, &rc);
+  return rc;
+}
+
+static void fts3EvalZeroPoslist(Fts3Phrase *pPhrase){
+  if( pPhrase->doclist.bFreeList ){
+    sqlite3_free(pPhrase->doclist.pList);
+  }
+  pPhrase->doclist.pList = 0;
+  pPhrase->doclist.nList = 0;
+  pPhrase->doclist.bFreeList = 0;
+}
+
+static int fts3EvalNearTrim2(
+  int nNear,
+  char *aTmp,                     /* Temporary space to use */
+  char **paPoslist,               /* IN/OUT: Position list */
+  int *pnToken,                   /* IN/OUT: Tokens in phrase of *paPoslist */
+  Fts3Phrase *pPhrase             /* The phrase object to trim the doclist of */
+){
+  int nParam1 = nNear + pPhrase->nToken;
+  int nParam2 = nNear + *pnToken;
+  int nNew;
+  char *p2; 
+  char *pOut; 
+  int res;
+
+  assert( pPhrase->doclist.pList );
+
+  p2 = pOut = pPhrase->doclist.pList;
+  res = fts3PoslistNearMerge(
+    &pOut, aTmp, nParam1, nParam2, paPoslist, &p2
+  );
+  if( res ){
+    nNew = (pOut - pPhrase->doclist.pList) - 1;
+    assert( pPhrase->doclist.pList[nNew]=='\0' );
+    assert( nNew<=pPhrase->doclist.nList && nNew>0 );
+    memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
+    pPhrase->doclist.nList = nNew;
+    *paPoslist = pPhrase->doclist.pList;
+    *pnToken = pPhrase->nToken;
+  }
+
+  return res;
+}
+
+static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
+  int res = 1;
+
+  /* The following block runs if pExpr is the root of a NEAR query.
+  ** For example, the query:
+  **
+  **         "w" NEAR "x" NEAR "y" NEAR "z"
+  **
+  ** which is represented in tree form as:
+  **
+  **                               |
+  **                          +--NEAR--+      <-- root of NEAR query
+  **                          |        |
+  **                     +--NEAR--+   "z"
+  **                     |        |
+  **                +--NEAR--+   "y"
+  **                |        |
+  **               "w"      "x"
+  **
+  ** The right-hand child of a NEAR node is always a phrase. The 
+  ** left-hand child may be either a phrase or a NEAR node. There are
+  ** no exceptions to this.
+  */
+  if( *pRc==SQLITE_OK 
+   && pExpr->eType==FTSQUERY_NEAR 
+   && pExpr->bEof==0
+   && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
+  ){
+    Fts3Expr *p; 
+    int nTmp = 0;                 /* Bytes of temp space */
+    char *aTmp;                   /* Temp space for PoslistNearMerge() */
+
+    /* Allocate temporary working space. */
+    for(p=pExpr; p->pLeft; p=p->pLeft){
+      nTmp += p->pRight->pPhrase->doclist.nList;
+    }
+    nTmp += p->pPhrase->doclist.nList;
+    aTmp = sqlite3_malloc(nTmp*2);
+    if( !aTmp ){
+      *pRc = SQLITE_NOMEM;
+      res = 0;
+    }else{
+      char *aPoslist = p->pPhrase->doclist.pList;
+      int nToken = p->pPhrase->nToken;
+
+      for(p=p->pParent;res && p && p->eType==FTSQUERY_NEAR; p=p->pParent){
+        Fts3Phrase *pPhrase = p->pRight->pPhrase;
+        int nNear = p->nNear;
+        res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+      }
+  
+      aPoslist = pExpr->pRight->pPhrase->doclist.pList;
+      nToken = pExpr->pRight->pPhrase->nToken;
+      for(p=pExpr->pLeft; p && res; p=p->pLeft){
+        int nNear = p->pParent->nNear;
+        Fts3Phrase *pPhrase = (
+            p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
+        );
+        res = fts3EvalNearTrim2(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+      }
+    }
+
+    sqlite3_free(aTmp);
+  }
+
+  return res;
+}
+
+/*
+** This macro is used by the fts3EvalNext() function. The two arguments are
+** 64-bit docid values. If the current query is "ORDER BY docid ASC", then
+** the macro returns (i1 - i2). Or if it is "ORDER BY docid DESC", then
+** it returns (i2 - i1). This allows the same code to be used for merging
+** doclists in ascending or descending order.
+*/
+#define DOCID_CMP(i1, i2) ((pCsr->bDesc?-1:1) * (i1-i2))
+
+static void fts3EvalNext(
+  Fts3Cursor *pCsr, 
+  Fts3Expr *pExpr, 
+  int *pRc
+){
+  if( *pRc==SQLITE_OK ){
+    assert( pExpr->bEof==0 );
+    pExpr->bStart = 1;
+
+    switch( pExpr->eType ){
+      case FTSQUERY_NEAR:
+      case FTSQUERY_AND: {
+        Fts3Expr *pLeft = pExpr->pLeft;
+        Fts3Expr *pRight = pExpr->pRight;
+        assert( !pLeft->bDeferred || !pRight->bDeferred );
+        if( pLeft->bDeferred ){
+          fts3EvalNext(pCsr, pRight, pRc);
+          pExpr->iDocid = pRight->iDocid;
+          pExpr->bEof = pRight->bEof;
+        }else if( pRight->bDeferred ){
+          fts3EvalNext(pCsr, pLeft, pRc);
+          pExpr->iDocid = pLeft->iDocid;
+          pExpr->bEof = pLeft->bEof;
+        }else{
+          fts3EvalNext(pCsr, pLeft, pRc);
+          fts3EvalNext(pCsr, pRight, pRc);
+
+          while( !pLeft->bEof && !pRight->bEof && *pRc==SQLITE_OK ){
+            sqlite3_int64 iDiff = DOCID_CMP(pLeft->iDocid, pRight->iDocid);
+            if( iDiff==0 ) break;
+            if( iDiff<0 ){
+              fts3EvalNext(pCsr, pLeft, pRc);
+            }else{
+              fts3EvalNext(pCsr, pRight, pRc);
+            }
+          }
+
+          pExpr->iDocid = pLeft->iDocid;
+          pExpr->bEof = (pLeft->bEof || pRight->bEof);
+        }
+        break;
+      }
+  
+      case FTSQUERY_OR: {
+        Fts3Expr *pLeft = pExpr->pLeft;
+        Fts3Expr *pRight = pExpr->pRight;
+        sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid);
+
+        assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid );
+        assert( pRight->bStart || pLeft->iDocid==pRight->iDocid );
+
+        if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
+          fts3EvalNext(pCsr, pLeft, pRc);
+        }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
+          fts3EvalNext(pCsr, pRight, pRc);
+        }else{
+          fts3EvalNext(pCsr, pLeft, pRc);
+          fts3EvalNext(pCsr, pRight, pRc);
+        }
+
+        pExpr->bEof = (pLeft->bEof && pRight->bEof);
+        iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid);
+        if( pRight->bEof || (pLeft->bEof==0 &&  iCmp<0) ){
+          pExpr->iDocid = pLeft->iDocid;
+        }else{
+          pExpr->iDocid = pRight->iDocid;
+        }
+
+        break;
+      }
+
+      case FTSQUERY_NOT: {
+        Fts3Expr *pLeft = pExpr->pLeft;
+        Fts3Expr *pRight = pExpr->pRight;
+
+        if( pRight->bStart==0 ){
+          fts3EvalNext(pCsr, pRight, pRc);
+          assert( *pRc!=SQLITE_OK || pRight->bStart );
+        }
+
+        fts3EvalNext(pCsr, pLeft, pRc);
+        if( pLeft->bEof==0 ){
+          while( !*pRc 
+              && !pRight->bEof 
+              && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0 
+          ){
+            fts3EvalNext(pCsr, pRight, pRc);
+          }
+        }
+        pExpr->iDocid = pLeft->iDocid;
+        pExpr->bEof = pLeft->bEof;
+        break;
+      }
+
+      default: {
+        Fts3Phrase *pPhrase = pExpr->pPhrase;
+        fts3EvalZeroPoslist(pPhrase);
+        *pRc = fts3EvalPhraseNext(pCsr, pPhrase, &pExpr->bEof);
+        pExpr->iDocid = pPhrase->doclist.iDocid;
+        break;
+      }
+    }
+  }
+}
+
+static int fts3EvalDeferredTest(Fts3Cursor *pCsr, Fts3Expr *pExpr, int *pRc){
+  int bHit = 1;
+  if( *pRc==SQLITE_OK ){
+    switch( pExpr->eType ){
+      case FTSQUERY_NEAR:
+      case FTSQUERY_AND:
+        bHit = (
+            fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc)
+         && fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc)
+         && fts3EvalNearTest(pExpr, pRc)
+        );
+
+        /* If the NEAR expression does not match any rows, zero the doclist for 
+        ** all phrases involved in the NEAR. This is because the snippet(),
+        ** offsets() and matchinfo() functions are not supposed to recognize 
+        ** any instances of phrases that are part of unmatched NEAR queries. 
+        ** For example if this expression:
+        **
+        **    ... MATCH 'a OR (b NEAR c)'
+        **
+        ** is matched against a row containing:
+        **
+        **        'a b d e'
+        **
+        ** then any snippet() should ony highlight the "a" term, not the "b"
+        ** (as "b" is part of a non-matching NEAR clause).
+        */
+        if( bHit==0 
+         && pExpr->eType==FTSQUERY_NEAR 
+         && (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
+        ){
+          Fts3Expr *p;
+          for(p=pExpr; p->pPhrase==0; p=p->pLeft){
+            if( p->pRight->iDocid==pCsr->iPrevId ){
+              fts3EvalZeroPoslist(p->pRight->pPhrase);
+            }
+          }
+          if( p->iDocid==pCsr->iPrevId ){
+            fts3EvalZeroPoslist(p->pPhrase);
+          }
+        }
+
+        break;
+
+      case FTSQUERY_OR: {
+        int bHit1 = fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc);
+        int bHit2 = fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc);
+        bHit = bHit1 || bHit2;
+        break;
+      }
+
+      case FTSQUERY_NOT:
+        bHit = (
+            fts3EvalDeferredTest(pCsr, pExpr->pLeft, pRc)
+         && !fts3EvalDeferredTest(pCsr, pExpr->pRight, pRc)
+        );
+        break;
+
+      default: {
+        if( pCsr->pDeferred 
+         && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred)
+        ){
+          Fts3Phrase *pPhrase = pExpr->pPhrase;
+          assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 );
+          if( pExpr->bDeferred ){
+            fts3EvalZeroPoslist(pPhrase);
+          }
+          *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase);
+          bHit = (pPhrase->doclist.pList!=0);
+          pExpr->iDocid = pCsr->iPrevId;
+        }else{
+          bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
+        }
+        break;
+      }
+    }
+  }
+  return bHit;
+}
+
+/*
+** Return 1 if both of the following are true:
+**
+**   1. *pRc is SQLITE_OK when this function returns, and
+**
+**   2. After scanning the current FTS table row for the deferred tokens,
+**      it is determined that the row does not match the query.
+**
+** Or, if no error occurs and it seems the current row does match the FTS
+** query, return 0.
+*/
+static int fts3EvalLoadDeferred(Fts3Cursor *pCsr, int *pRc){
+  int rc = *pRc;
+  int bMiss = 0;
+  if( rc==SQLITE_OK ){
+    if( pCsr->pDeferred ){
+      rc = fts3CursorSeek(0, pCsr);
+      if( rc==SQLITE_OK ){
+        rc = sqlite3Fts3CacheDeferredDoclists(pCsr);
+      }
+    }
+    bMiss = (0==fts3EvalDeferredTest(pCsr, pCsr->pExpr, &rc));
+    sqlite3Fts3FreeDeferredDoclists(pCsr);
+    *pRc = rc;
+  }
+  return (rc==SQLITE_OK && bMiss);
+}
+
+/*
+** Advance to the next document that matches the FTS expression in
+** Fts3Cursor.pExpr.
+*/
+SQLITE_PRIVATE int sqlite3Fts3EvalNext(Fts3Cursor *pCsr){
+  int rc = SQLITE_OK;             /* Return Code */
+  Fts3Expr *pExpr = pCsr->pExpr;
+  assert( pCsr->isEof==0 );
+  if( pExpr==0 ){
+    pCsr->isEof = 1;
+  }else{
+    do {
+      if( pCsr->isRequireSeek==0 ){
+        sqlite3_reset(pCsr->pStmt);
+      }
+      assert( sqlite3_data_count(pCsr->pStmt)==0 );
+      fts3EvalNext(pCsr, pExpr, &rc);
+      pCsr->isEof = pExpr->bEof;
+      pCsr->isRequireSeek = 1;
+      pCsr->isMatchinfoNeeded = 1;
+      pCsr->iPrevId = pExpr->iDocid;
+    }while( pCsr->isEof==0 && fts3EvalLoadDeferred(pCsr, &rc) );
+  }
+  return rc;
+}
+
+/*
+** Restart interation for expression pExpr so that the next call to
+** sqlite3Fts3EvalNext() visits the first row. Do not allow incremental 
+** loading or merging of phrase doclists for this iteration.
+**
+** If *pRc is other than SQLITE_OK when this function is called, it is
+** a no-op. If an error occurs within this function, *pRc is set to an
+** SQLite error code before returning.
+*/
+static void fts3EvalRestart(
+  Fts3Cursor *pCsr,
+  Fts3Expr *pExpr,
+  int *pRc
+){
+  if( pExpr && *pRc==SQLITE_OK ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+
+    if( pPhrase ){
+      fts3EvalZeroPoslist(pPhrase);
+      if( pPhrase->bIncr ){
+        assert( pPhrase->nToken==1 );
+        assert( pPhrase->aToken[0].pSegcsr );
+        sqlite3Fts3MsrIncrRestart(pPhrase->aToken[0].pSegcsr);
+        *pRc = fts3EvalPhraseStart(pCsr, 0, pPhrase);
+      }
+
+      pPhrase->doclist.pNextDocid = 0;
+      pPhrase->doclist.iDocid = 0;
+    }
+
+    pExpr->iDocid = 0;
+    pExpr->bEof = 0;
+    pExpr->bStart = 0;
+
+    fts3EvalRestart(pCsr, pExpr->pLeft, pRc);
+    fts3EvalRestart(pCsr, pExpr->pRight, pRc);
+  }
+}
+
+/*
+** After allocating the Fts3Expr.aMI[] array for each phrase in the 
+** expression rooted at pExpr, the cursor iterates through all rows matched
+** by pExpr, calling this function for each row. This function increments
+** the values in Fts3Expr.aMI[] according to the position-list currently
+** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase 
+** expression nodes.
+*/
+static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
+  if( pExpr ){
+    Fts3Phrase *pPhrase = pExpr->pPhrase;
+    if( pPhrase && pPhrase->doclist.pList ){
+      int iCol = 0;
+      char *p = pPhrase->doclist.pList;
+
+      assert( *p );
+      while( 1 ){
+        u8 c = 0;
+        int iCnt = 0;
+        while( 0xFE & (*p | c) ){
+          if( (c&0x80)==0 ) iCnt++;
+          c = *p++ & 0x80;
+        }
+
+        /* aMI[iCol*3 + 1] = Number of occurrences
+        ** aMI[iCol*3 + 2] = Number of rows containing at least one instance
+        */
+        pExpr->aMI[iCol*3 + 1] += iCnt;
+        pExpr->aMI[iCol*3 + 2] += (iCnt>0);
+        if( *p==0x00 ) break;
+        p++;
+        p += sqlite3Fts3GetVarint32(p, &iCol);
+      }
+    }
+
+    fts3EvalUpdateCounts(pExpr->pLeft);
+    fts3EvalUpdateCounts(pExpr->pRight);
+  }
+}
+
+/*
+** Expression pExpr must be of type FTSQUERY_PHRASE.
+**
+** If it is not already allocated and populated, this function allocates and
+** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part
+** of a NEAR expression, then it also allocates and populates the same array
+** for all other phrases that are part of the NEAR expression.
+**
+** SQLITE_OK is returned if the aMI[] array is successfully allocated and
+** populated. Otherwise, if an error occurs, an SQLite error code is returned.
+*/
+static int fts3EvalGatherStats(
+  Fts3Cursor *pCsr,               /* Cursor object */
+  Fts3Expr *pExpr                 /* FTSQUERY_PHRASE expression */
+){
+  int rc = SQLITE_OK;             /* Return code */
+
+  assert( pExpr->eType==FTSQUERY_PHRASE );
+  if( pExpr->aMI==0 ){
+    Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+    Fts3Expr *pRoot;                /* Root of NEAR expression */
+    Fts3Expr *p;                    /* Iterator used for several purposes */
+
+    sqlite3_int64 iPrevId = pCsr->iPrevId;
+    sqlite3_int64 iDocid;
+    u8 bEof;
+
+    /* Find the root of the NEAR expression */
+    pRoot = pExpr;
+    while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){
+      pRoot = pRoot->pParent;
+    }
+    iDocid = pRoot->iDocid;
+    bEof = pRoot->bEof;
+    assert( pRoot->bStart );
+
+    /* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */
+    for(p=pRoot; p; p=p->pLeft){
+      Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
+      assert( pE->aMI==0 );
+      pE->aMI = (u32 *)sqlite3_malloc(pTab->nColumn * 3 * sizeof(u32));
+      if( !pE->aMI ) return SQLITE_NOMEM;
+      memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
+    }
+
+    fts3EvalRestart(pCsr, pRoot, &rc);
+
+    while( pCsr->isEof==0 && rc==SQLITE_OK ){
+
+      do {
+        /* Ensure the %_content statement is reset. */
+        if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt);
+        assert( sqlite3_data_count(pCsr->pStmt)==0 );
+
+        /* Advance to the next document */
+        fts3EvalNext(pCsr, pRoot, &rc);
+        pCsr->isEof = pRoot->bEof;
+        pCsr->isRequireSeek = 1;
+        pCsr->isMatchinfoNeeded = 1;
+        pCsr->iPrevId = pRoot->iDocid;
+      }while( pCsr->isEof==0 
+           && pRoot->eType==FTSQUERY_NEAR 
+           && fts3EvalLoadDeferred(pCsr, &rc) 
+      );
+
+      if( rc==SQLITE_OK && pCsr->isEof==0 ){
+        fts3EvalUpdateCounts(pRoot);
+      }
+    }
+
+    pCsr->isEof = 0;
+    pCsr->iPrevId = iPrevId;
+
+    if( bEof ){
+      pRoot->bEof = bEof;
+    }else{
+      /* Caution: pRoot may iterate through docids in ascending or descending
+      ** order. For this reason, even though it seems more defensive, the 
+      ** do loop can not be written:
+      **
+      **   do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK );
+      */
+      fts3EvalRestart(pCsr, pRoot, &rc);
+      do {
+        fts3EvalNext(pCsr, pRoot, &rc);
+        assert( pRoot->bEof==0 );
+      }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
+      fts3EvalLoadDeferred(pCsr, &rc);
+    }
+  }
+  return rc;
+}
+
+/*
+** This function is used by the matchinfo() module to query a phrase 
+** expression node for the following information:
+**
+**   1. The total number of occurrences of the phrase in each column of 
+**      the FTS table (considering all rows), and
+**
+**   2. For each column, the number of rows in the table for which the
+**      column contains at least one instance of the phrase.
+**
+** If no error occurs, SQLITE_OK is returned and the values for each column
+** written into the array aiOut as follows:
+**
+**   aiOut[iCol*3 + 1] = Number of occurrences
+**   aiOut[iCol*3 + 2] = Number of rows containing at least one instance
+**
+** Caveats:
+**
+**   * If a phrase consists entirely of deferred tokens, then all output 
+**     values are set to the number of documents in the table. In other
+**     words we assume that very common tokens occur exactly once in each 
+**     column of each row of the table.
+**
+**   * If a phrase contains some deferred tokens (and some non-deferred 
+**     tokens), count the potential occurrence identified by considering
+**     the non-deferred tokens instead of actual phrase occurrences.
+**
+**   * If the phrase is part of a NEAR expression, then only phrase instances
+**     that meet the NEAR constraint are included in the counts.
+*/
+SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(
+  Fts3Cursor *pCsr,               /* FTS cursor handle */
+  Fts3Expr *pExpr,                /* Phrase expression */
+  u32 *aiOut                      /* Array to write results into (see above) */
+){
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  int rc = SQLITE_OK;
+  int iCol;
+
+  if( pExpr->bDeferred && pExpr->pParent->eType!=FTSQUERY_NEAR ){
+    assert( pCsr->nDoc>0 );
+    for(iCol=0; iCol<pTab->nColumn; iCol++){
+      aiOut[iCol*3 + 1] = (u32)pCsr->nDoc;
+      aiOut[iCol*3 + 2] = (u32)pCsr->nDoc;
+    }
+  }else{
+    rc = fts3EvalGatherStats(pCsr, pExpr);
+    if( rc==SQLITE_OK ){
+      assert( pExpr->aMI );
+      for(iCol=0; iCol<pTab->nColumn; iCol++){
+        aiOut[iCol*3 + 1] = pExpr->aMI[iCol*3 + 1];
+        aiOut[iCol*3 + 2] = pExpr->aMI[iCol*3 + 2];
+      }
+    }
+  }
+
+  return rc;
+}
+
+/*
+** The expression pExpr passed as the second argument to this function
+** must be of type FTSQUERY_PHRASE. 
+**
+** The returned value is either NULL or a pointer to a buffer containing
+** a position-list indicating the occurrences of the phrase in column iCol
+** of the current row. 
+**
+** More specifically, the returned buffer contains 1 varint for each 
+** occurence of the phrase in the column, stored using the normal (delta+2) 
+** compression and is terminated by either an 0x01 or 0x00 byte. For example,
+** if the requested column contains "a b X c d X X" and the position-list
+** for 'X' is requested, the buffer returned may contain:
+**
+**     0x04 0x05 0x03 0x01   or   0x04 0x05 0x03 0x00
+**
+** This function works regardless of whether or not the phrase is deferred,
+** incremental, or neither.
+*/
+SQLITE_PRIVATE char *sqlite3Fts3EvalPhrasePoslist(
+  Fts3Cursor *pCsr,               /* FTS3 cursor object */
+  Fts3Expr *pExpr,                /* Phrase to return doclist for */
+  int iCol                        /* Column to return position list for */
+){
+  Fts3Phrase *pPhrase = pExpr->pPhrase;
+  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
+  char *pIter = pPhrase->doclist.pList;
+  int iThis;
+
+  assert( iCol>=0 && iCol<pTab->nColumn );
+  if( !pIter 
+   || pExpr->bEof 
+   || pExpr->iDocid!=pCsr->iPrevId
+   || (pPhrase->iColumn<pTab->nColumn && pPhrase->iColumn!=iCol) 
+  ){
+    return 0;
+  }
+
+  assert( pPhrase->doclist.nList>0 );
+  if( *pIter==0x01 ){
+    pIter++;
+    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
+  }else{
+    iThis = 0;
+  }
+  while( iThis<iCol ){
+    fts3ColumnlistCopy(0, &pIter);
+    if( *pIter==0x00 ) return 0;
+    pIter++;
+    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
+  }
+
+  return ((iCol==iThis)?pIter:0);
+}
+
+/*
+** Free all components of the Fts3Phrase structure that were allocated by
+** the eval module. Specifically, this means to free:
+**
+**   * the contents of pPhrase->doclist, and
+**   * any Fts3MultiSegReader objects held by phrase tokens.
+*/
+SQLITE_PRIVATE void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *pPhrase){
+  if( pPhrase ){
+    int i;
+    sqlite3_free(pPhrase->doclist.aAll);
+    fts3EvalZeroPoslist(pPhrase);
+    memset(&pPhrase->doclist, 0, sizeof(Fts3Doclist));
+    for(i=0; i<pPhrase->nToken; i++){
+      fts3SegReaderCursorFree(pPhrase->aToken[i].pSegcsr);
+      pPhrase->aToken[i].pSegcsr = 0;
+    }
+  }
+}
+
 #endif
 
 /************** End of fts3.c ************************************************/
@@ -114471,7 +116446,6 @@ SQLITE_API int sqlite3_extension_init(
 ******************************************************************************
 **
 */
-
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
 
 
@@ -114485,7 +116459,7 @@ struct Fts3auxTable {
 
 struct Fts3auxCursor {
   sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
-  Fts3SegReaderCursor csr;        /* Must be right after "base" */
+  Fts3MultiSegReader csr;        /* Must be right after "base" */
   Fts3SegFilter filter;
   char *zStop;
   int nStop;                      /* Byte-length of string zStop */
@@ -114553,6 +116527,7 @@ static int fts3auxConnectMethod(
   p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
   p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
   p->pFts3Tab->db = db;
+  p->pFts3Tab->nIndex = 1;
 
   memcpy((char *)p->pFts3Tab->zDb, zDb, nDb);
   memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3);
@@ -114799,6 +116774,7 @@ static int fts3auxFilterMethod(
   int isScan;
 
   UNUSED_PARAMETER(nVal);
+  UNUSED_PARAMETER(idxStr);
 
   assert( idxStr==0 );
   assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0
@@ -114832,7 +116808,7 @@ static int fts3auxFilterMethod(
     if( pCsr->zStop==0 ) return SQLITE_NOMEM;
   }
 
-  rc = sqlite3Fts3SegReaderCursor(pFts3, FTS3_SEGCURSOR_ALL,
+  rc = sqlite3Fts3SegReaderCursor(pFts3, 0, FTS3_SEGCURSOR_ALL,
       pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
   );
   if( rc==SQLITE_OK ){
@@ -114916,7 +116892,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
      0,                           /* xCommit       */
      0,                           /* xRollback     */
      0,                           /* xFindFunction */
-     0                            /* xRename       */
+     0,                           /* xRename       */
+     0,                           /* xSavepoint    */
+     0,                           /* xRelease      */
+     0                            /* xRollbackTo   */
   };
   int rc;                         /* Return code */
 
@@ -115008,12 +116987,21 @@ SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
 #define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10
 
 
+/*
+** isNot:
+**   This variable is used by function getNextNode(). When getNextNode() is
+**   called, it sets ParseContext.isNot to true if the 'next node' is a 
+**   FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the
+**   FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to
+**   zero.
+*/
 typedef struct ParseContext ParseContext;
 struct ParseContext {
   sqlite3_tokenizer *pTokenizer;      /* Tokenizer module */
   const char **azCol;                 /* Array of column names for fts3 table */
   int nCol;                           /* Number of entries in azCol[] */
   int iDefaultCol;                    /* Default column to query */
+  int isNot;                          /* True if getNextNode() sees a unary - */
   sqlite3_context *pCtx;              /* Write error message here */
   int nNest;                          /* Number of nested brackets */
 };
@@ -115099,7 +117087,7 @@ static int getNextToken(
           iEnd++;
         }
         if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
-          pRet->pPhrase->isNot = 1;
+          pParse->isNot = 1;
         }
       }
       nConsumed = iEnd;
@@ -115151,36 +117139,55 @@ static int getNextString(
   char *zTemp = 0;
   int nTemp = 0;
 
+  const int nSpace = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
+  int nToken = 0;
+
+  /* The final Fts3Expr data structure, including the Fts3Phrase,
+  ** Fts3PhraseToken structures token buffers are all stored as a single 
+  ** allocation so that the expression can be freed with a single call to
+  ** sqlite3_free(). Setting this up requires a two pass approach.
+  **
+  ** The first pass, in the block below, uses a tokenizer cursor to iterate
+  ** through the tokens in the expression. This pass uses fts3ReallocOrFree()
+  ** to assemble data in two dynamic buffers:
+  **
+  **   Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase
+  **             structure, followed by the array of Fts3PhraseToken 
+  **             structures. This pass only populates the Fts3PhraseToken array.
+  **
+  **   Buffer zTemp: Contains copies of all tokens.
+  **
+  ** The second pass, in the block that begins "if( rc==SQLITE_DONE )" below,
+  ** appends buffer zTemp to buffer p, and fills in the Fts3Expr and Fts3Phrase
+  ** structures.
+  */
   rc = pModule->xOpen(pTokenizer, zInput, nInput, &pCursor);
   if( rc==SQLITE_OK ){
     int ii;
     pCursor->pTokenizer = pTokenizer;
     for(ii=0; rc==SQLITE_OK; ii++){
-      const char *zToken;
-      int nToken, iBegin, iEnd, iPos;
-      rc = pModule->xNext(pCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos);
+      const char *zByte;
+      int nByte, iBegin, iEnd, iPos;
+      rc = pModule->xNext(pCursor, &zByte, &nByte, &iBegin, &iEnd, &iPos);
       if( rc==SQLITE_OK ){
-        int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
-        p = fts3ReallocOrFree(p, nByte+ii*sizeof(Fts3PhraseToken));
-        zTemp = fts3ReallocOrFree(zTemp, nTemp + nToken);
-        if( !p || !zTemp ){
-          goto no_mem;
-        }
-        if( ii==0 ){
-          memset(p, 0, nByte);
-          p->pPhrase = (Fts3Phrase *)&p[1];
-        }
-        p->pPhrase = (Fts3Phrase *)&p[1];
-        memset(&p->pPhrase->aToken[ii], 0, sizeof(Fts3PhraseToken));
-        p->pPhrase->nToken = ii+1;
-        p->pPhrase->aToken[ii].n = nToken;
-        memcpy(&zTemp[nTemp], zToken, nToken);
-        nTemp += nToken;
-        if( iEnd<nInput && zInput[iEnd]=='*' ){
-          p->pPhrase->aToken[ii].isPrefix = 1;
-        }else{
-          p->pPhrase->aToken[ii].isPrefix = 0;
-        }
+        Fts3PhraseToken *pToken;
+
+        p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
+        if( !p ) goto no_mem;
+
+        zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
+        if( !zTemp ) goto no_mem;
+
+        assert( nToken==ii );
+        pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
+        memset(pToken, 0, sizeof(Fts3PhraseToken));
+
+        memcpy(&zTemp[nTemp], zByte, nByte);
+        nTemp += nByte;
+
+        pToken->n = nByte;
+        pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
+        nToken = ii+1;
       }
     }
 
@@ -115190,28 +117197,24 @@ static int getNextString(
 
   if( rc==SQLITE_DONE ){
     int jj;
-    char *zNew = NULL;
-    int nNew = 0;
-    int nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase);
-    nByte += (p?(p->pPhrase->nToken-1):0) * sizeof(Fts3PhraseToken);
-    p = fts3ReallocOrFree(p, nByte + nTemp);
-    if( !p ){
-      goto no_mem;
-    }
-    if( zTemp ){
-      zNew = &(((char *)p)[nByte]);
-      memcpy(zNew, zTemp, nTemp);
-    }else{
-      memset(p, 0, nByte+nTemp);
-    }
+    char *zBuf = 0;
+
+    p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
+    if( !p ) goto no_mem;
+    memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
+    p->eType = FTSQUERY_PHRASE;
     p->pPhrase = (Fts3Phrase *)&p[1];
+    p->pPhrase->iColumn = pParse->iDefaultCol;
+    p->pPhrase->nToken = nToken;
+
+    zBuf = (char *)&p->pPhrase->aToken[nToken];
+    memcpy(zBuf, zTemp, nTemp);
+    sqlite3_free(zTemp);
+
     for(jj=0; jj<p->pPhrase->nToken; jj++){
-      p->pPhrase->aToken[jj].z = &zNew[nNew];
-      nNew += p->pPhrase->aToken[jj].n;
+      p->pPhrase->aToken[jj].z = zBuf;
+      zBuf += p->pPhrase->aToken[jj].n;
     }
-    sqlite3_free(zTemp);
-    p->eType = FTSQUERY_PHRASE;
-    p->pPhrase->iColumn = pParse->iDefaultCol;
     rc = SQLITE_OK;
   }
 
@@ -115268,6 +117271,8 @@ static int getNextNode(
   const char *zInput = z;
   int nInput = n;
 
+  pParse->isNot = 0;
+
   /* Skip over any whitespace before checking for a keyword, an open or
   ** close bracket, or a quoted string. 
   */
@@ -115486,7 +117491,7 @@ static int fts3ExprParse(
       int isPhrase;
 
       if( !sqlite3_fts3_enable_parentheses 
-       && p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot 
+       && p->eType==FTSQUERY_PHRASE && pParse->isNot 
       ){
         /* Create an implicit NOT operator. */
         Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
@@ -115504,7 +117509,6 @@ static int fts3ExprParse(
         p = pPrev;
       }else{
         int eType = p->eType;
-        assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot );
         isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
 
         /* The isRequirePhrase variable is set to true if a phrase or
@@ -115667,9 +117671,11 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
 */
 SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *p){
   if( p ){
+    assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
     sqlite3Fts3ExprFree(p->pLeft);
     sqlite3Fts3ExprFree(p->pRight);
-    sqlite3_free(p->aDoclist);
+    sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
+    sqlite3_free(p->aMI);
     sqlite3_free(p);
   }
 }
@@ -115726,7 +117732,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
       Fts3Phrase *pPhrase = pExpr->pPhrase;
       int i;
       zBuf = sqlite3_mprintf(
-          "%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
+          "%zPHRASE %d 0", zBuf, pPhrase->iColumn);
       for(i=0; zBuf && i<pPhrase->nToken; i++){
         zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, 
             pPhrase->aToken[i].n, pPhrase->aToken[i].z,
@@ -116273,7 +118279,6 @@ SQLITE_PRIVATE void *sqlite3Fts3HashInsert(
 
 
 
-
 /*
 ** Class derived from sqlite3_tokenizer
 */
@@ -116913,12 +118918,12 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
 **     * The FTS3 module is being built into the core of
 **       SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
 */
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-
 #ifndef SQLITE_CORE
   SQLITE_EXTENSION_INIT1
 #endif
 
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+
 
 /*
 ** Implementation of the SQL scalar function for accessing the underlying 
@@ -117042,7 +119047,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
 ){
   int rc;
   char *z = (char *)zArg;
-  int n;
+  int n = 0;
   char *zCopy;
   char *zEnd;                     /* Pointer to nul-term of zCopy */
   sqlite3_tokenizer_module *m;
@@ -117407,7 +119412,6 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
 
 
 
-
 typedef struct simple_tokenizer {
   sqlite3_tokenizer base;
   char delim[128];             /* flag ASCII delimiters */
@@ -117644,14 +119648,40 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
 */
 #define FTS3_NODE_PADDING (FTS3_VARINT_MAX*2)
 
+/*
+** Under certain circumstances, b-tree nodes (doclists) can be loaded into
+** memory incrementally instead of all at once. This can be a big performance
+** win (reduced IO and CPU) if SQLite stops calling the virtual table xNext()
+** method before retrieving all query results (as may happen, for example,
+** if a query has a LIMIT clause).
+**
+** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD 
+** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes.
+** The code is written so that the hard lower-limit for each of these values 
+** is 1. Clearly such small values would be inefficient, but can be useful 
+** for testing purposes.
+**
+** If this module is built with SQLITE_TEST defined, these constants may
+** be overridden at runtime for testing purposes. File fts3_test.c contains
+** a Tcl interface to read and write the values.
+*/
+#ifdef SQLITE_TEST
+int test_fts3_node_chunksize = (4*1024);
+int test_fts3_node_chunk_threshold = (4*1024)*4;
+# define FTS3_NODE_CHUNKSIZE       test_fts3_node_chunksize
+# define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold
+#else
+# define FTS3_NODE_CHUNKSIZE (4*1024) 
+# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4)
+#endif
+
 typedef struct PendingList PendingList;
 typedef struct SegmentNode SegmentNode;
 typedef struct SegmentWriter SegmentWriter;
 
 /*
-** Data structure used while accumulating terms in the pending-terms hash
-** table. The hash table entry maps from term (a string) to a malloc'd
-** instance of this structure.
+** An instance of the following data structure is used to build doclists
+** incrementally. See function fts3PendingListAppend() for details.
 */
 struct PendingList {
   int nData;
@@ -117682,7 +119712,6 @@ struct Fts3DeferredToken {
 **
 **   sqlite3Fts3SegReaderNew()
 **   sqlite3Fts3SegReaderFree()
-**   sqlite3Fts3SegReaderCost()
 **   sqlite3Fts3SegReaderIterate()
 **
 ** Methods used to manipulate Fts3SegReader structures:
@@ -117701,6 +119730,9 @@ struct Fts3SegReader {
 
   char *aNode;                    /* Pointer to node data (or NULL) */
   int nNode;                      /* Size of buffer at aNode (or 0) */
+  int nPopulate;                  /* If >0, bytes of buffer aNode[] loaded */
+  sqlite3_blob *pBlob;            /* If not NULL, blob handle to read node */
+
   Fts3HashElem **ppNextElem;
 
   /* Variables set by fts3SegReaderNext(). These may be read directly
@@ -117714,8 +119746,11 @@ struct Fts3SegReader {
   char *aDoclist;                 /* Pointer to doclist of current entry */
   int nDoclist;                   /* Size of doclist in current entry */
 
-  /* The following variables are used to iterate through the current doclist */
+  /* The following variables are used by fts3SegReaderNextDocid() to iterate 
+  ** through the current doclist (aDoclist/nDoclist).
+  */
   char *pOffsetList;
+  int nOffsetList;                /* For descending pending seg-readers only */
   sqlite3_int64 iDocid;
 };
 
@@ -117753,6 +119788,14 @@ struct SegmentWriter {
 **   fts3NodeAddTerm()
 **   fts3NodeWrite()
 **   fts3NodeFree()
+**
+** When a b+tree is written to the database (either as a result of a merge
+** or the pending-terms table being flushed), leaves are written into the 
+** database file as soon as they are completely populated. The interior of
+** the tree is assembled in memory and written out only once all leaves have
+** been populated and stored. This is Ok, as the b+-tree fanout is usually
+** very large, meaning that the interior of the tree consumes relatively 
+** little memory.
 */
 struct SegmentNode {
   SegmentNode *pParent;           /* Parent node (or NULL for root node) */
@@ -117783,10 +119826,10 @@ struct SegmentNode {
 #define SQL_NEXT_SEGMENTS_ID          10
 #define SQL_INSERT_SEGDIR             11
 #define SQL_SELECT_LEVEL              12
-#define SQL_SELECT_ALL_LEVEL          13
+#define SQL_SELECT_LEVEL_RANGE        13
 #define SQL_SELECT_LEVEL_COUNT        14
-#define SQL_SELECT_SEGDIR_COUNT_MAX   15
-#define SQL_DELETE_SEGDIR_BY_LEVEL    16
+#define SQL_SELECT_SEGDIR_MAX_LEVEL   15
+#define SQL_DELETE_SEGDIR_LEVEL       16
 #define SQL_DELETE_SEGMENTS_RANGE     17
 #define SQL_CONTENT_INSERT            18
 #define SQL_DELETE_DOCSIZE            19
@@ -117795,6 +119838,11 @@ struct SegmentNode {
 #define SQL_SELECT_DOCTOTAL           22
 #define SQL_REPLACE_DOCTOTAL          23
 
+#define SQL_SELECT_ALL_PREFIX_LEVEL   24
+#define SQL_DELETE_ALL_TERMS_SEGDIR   25
+
+#define SQL_DELETE_SEGDIR_RANGE       26
+
 /*
 ** This function is used to obtain an SQLite prepared statement handle
 ** for the statement identified by the second argument. If successful,
@@ -117830,10 +119878,11 @@ static int fts3SqlStmt(
 /* 12 */  "SELECT idx, start_block, leaves_end_block, end_block, root "
             "FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC",
 /* 13 */  "SELECT idx, start_block, leaves_end_block, end_block, root "
-            "FROM %Q.'%q_segdir' ORDER BY level DESC, idx ASC",
+            "FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?"
+            "ORDER BY level DESC, idx ASC",
 
 /* 14 */  "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?",
-/* 15 */  "SELECT count(*), max(level) FROM %Q.'%q_segdir'",
+/* 15 */  "SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
 
 /* 16 */  "DELETE FROM %Q.'%q_segdir' WHERE level = ?",
 /* 17 */  "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?",
@@ -117843,6 +119892,11 @@ static int fts3SqlStmt(
 /* 21 */  "SELECT size FROM %Q.'%q_docsize' WHERE docid=?",
 /* 22 */  "SELECT value FROM %Q.'%q_stat' WHERE id=0",
 /* 23 */  "REPLACE INTO %Q.'%q_stat' VALUES(0,?)",
+/* 24 */  "",
+/* 25 */  "",
+
+/* 26 */ "DELETE FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?",
+
   };
   int rc = SQLITE_OK;
   sqlite3_stmt *pStmt;
@@ -117899,7 +119953,7 @@ static int fts3SelectDocsize(
     rc = sqlite3_step(pStmt);
     if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){
       rc = sqlite3_reset(pStmt);
-      if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
+      if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB;
       pStmt = 0;
     }else{
       rc = SQLITE_OK;
@@ -117998,14 +120052,32 @@ SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
 **   3: end_block
 **   4: root
 */
-SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(Fts3Table *p, int iLevel, sqlite3_stmt **ppStmt){
+SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
+  Fts3Table *p,                   /* FTS3 table */
+  int iIndex,                     /* Index for p->aIndex[] */
+  int iLevel,                     /* Level to select */
+  sqlite3_stmt **ppStmt           /* OUT: Compiled statement */
+){
   int rc;
   sqlite3_stmt *pStmt = 0;
+
+  assert( iLevel==FTS3_SEGCURSOR_ALL || iLevel>=0 );
+  assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
+  assert( iIndex>=0 && iIndex<p->nIndex );
+
   if( iLevel<0 ){
-    rc = fts3SqlStmt(p, SQL_SELECT_ALL_LEVEL, &pStmt, 0);
+    /* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
+    rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
+    if( rc==SQLITE_OK ){ 
+      sqlite3_bind_int(pStmt, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
+      sqlite3_bind_int(pStmt, 2, (iIndex+1)*FTS3_SEGDIR_MAXLEVEL-1);
+    }
   }else{
+    /* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */
     rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
-    if( rc==SQLITE_OK ) sqlite3_bind_int(pStmt, 1, iLevel);
+    if( rc==SQLITE_OK ){ 
+      sqlite3_bind_int(pStmt, 1, iLevel+iIndex*FTS3_SEGDIR_MAXLEVEL);
+    }
   }
   *ppStmt = pStmt;
   return rc;
@@ -118120,6 +120192,47 @@ static int fts3PendingListAppend(
   return 0;
 }
 
+/*
+** Free a PendingList object allocated by fts3PendingListAppend().
+*/
+static void fts3PendingListDelete(PendingList *pList){
+  sqlite3_free(pList);
+}
+
+/*
+** Add an entry to one of the pending-terms hash tables.
+*/
+static int fts3PendingTermsAddOne(
+  Fts3Table *p,
+  int iCol,
+  int iPos,
+  Fts3Hash *pHash,                /* Pending terms hash table to add entry to */
+  const char *zToken,
+  int nToken
+){
+  PendingList *pList;
+  int rc = SQLITE_OK;
+
+  pList = (PendingList *)fts3HashFind(pHash, zToken, nToken);
+  if( pList ){
+    p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem));
+  }
+  if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
+    if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){
+      /* Malloc failed while inserting the new entry. This can only 
+      ** happen if there was no previous entry for this token.
+      */
+      assert( 0==fts3HashFind(pHash, zToken, nToken) );
+      sqlite3_free(pList);
+      rc = SQLITE_NOMEM;
+    }
+  }
+  if( rc==SQLITE_OK ){
+    p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem));
+  }
+  return rc;
+}
+
 /*
 ** Tokenize the nul-terminated string zText and add all tokens to the
 ** pending-terms hash-table. The docid used is that currently stored in
@@ -118150,6 +120263,14 @@ static int fts3PendingTermsAdd(
 
   assert( pTokenizer && pModule );
 
+  /* If the user has inserted a NULL value, this function may be called with
+  ** zText==0. In this case, add zero token entries to the hash table and 
+  ** return early. */
+  if( zText==0 ){
+    *pnWord = 0;
+    return SQLITE_OK;
+  }
+
   rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr);
   if( rc!=SQLITE_OK ){
     return rc;
@@ -118160,8 +120281,7 @@ static int fts3PendingTermsAdd(
   while( SQLITE_OK==rc
       && SQLITE_OK==(rc = xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos))
   ){
-    PendingList *pList;
+    int i;
     if( iPos>=nWord ) nWord = iPos+1;
 
     /* Positions cannot be negative; we use -1 as a terminator internally.
@@ -118172,22 +120292,19 @@ static int fts3PendingTermsAdd(
       break;
     }
 
-    pList = (PendingList *)fts3HashFind(&p->pendingTerms, zToken, nToken);
-    if( pList ){
-      p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem));
-    }
-    if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
-      if( pList==fts3HashInsert(&p->pendingTerms, zToken, nToken, pList) ){
-        /* Malloc failed while inserting the new entry. This can only 
-        ** happen if there was no previous entry for this token.
-        */
-        assert( 0==fts3HashFind(&p->pendingTerms, zToken, nToken) );
-        sqlite3_free(pList);
-        rc = SQLITE_NOMEM;
-      }
-    }
-    if( rc==SQLITE_OK ){
-      p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem));
+    /* Add the term to the terms index */
+    rc = fts3PendingTermsAddOne(
+        p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken
+    );
+    
+    /* Add the term to each of the prefix indexes that it is not too 
+    ** short for. */
+    for(i=1; rc==SQLITE_OK && i<p->nIndex; i++){
+      struct Fts3Index *pIndex = &p->aIndex[i];
+      if( nToken<pIndex->nPrefix ) continue;
+      rc = fts3PendingTermsAddOne(
+          p, iCol, iPos, &pIndex->hPending, zToken, pIndex->nPrefix
+      );
     }
   }
 
@@ -118217,14 +120334,19 @@ static int fts3PendingTermsDocid(Fts3Table *p, sqlite_int64 iDocid){
 }
 
 /*
-** Discard the contents of the pending-terms hash table. 
+** Discard the contents of the pending-terms hash tables
 */
 SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
-  Fts3HashElem *pElem;
-  for(pElem=fts3HashFirst(&p->pendingTerms); pElem; pElem=fts3HashNext(pElem)){
-    sqlite3_free(fts3HashData(pElem));
+  int i;
+  for(i=0; i<p->nIndex; i++){
+    Fts3HashElem *pElem;
+    Fts3Hash *pHash = &p->aIndex[i].hPending;
+    for(pElem=fts3HashFirst(pHash); pElem; pElem=fts3HashNext(pElem)){
+      PendingList *pList = (PendingList *)fts3HashData(pElem);
+      fts3PendingListDelete(pList);
+    }
+    fts3HashClear(pHash);
   }
-  fts3HashClear(&p->pendingTerms);
   p->nPendingData = 0;
 }
 
@@ -118240,11 +120362,9 @@ static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){
   int i;                          /* Iterator variable */
   for(i=2; i<p->nColumn+2; i++){
     const char *zText = (const char *)sqlite3_value_text(apVal[i]);
-    if( zText ){
-      int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]);
-      if( rc!=SQLITE_OK ){
-        return rc;
-      }
+    int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]);
+    if( rc!=SQLITE_OK ){
+      return rc;
     }
     aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]);
   }
@@ -118349,14 +120469,14 @@ static int fts3DeleteAll(Fts3Table *p){
 static void fts3DeleteTerms( 
   int *pRC,               /* Result code */
   Fts3Table *p,           /* The FTS table to delete from */
-  sqlite3_value **apVal,  /* apVal[] contains the docid to be deleted */
+  sqlite3_value *pRowid,  /* The docid to be deleted */
   u32 *aSz                /* Sizes of deleted document written here */
 ){
   int rc;
   sqlite3_stmt *pSelect;
 
   if( *pRC ) return;
-  rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal);
+  rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid);
   if( rc==SQLITE_OK ){
     if( SQLITE_ROW==sqlite3_step(pSelect) ){
       int i;
@@ -118382,7 +120502,7 @@ static void fts3DeleteTerms(
 ** Forward declaration to account for the circular dependency between
 ** functions fts3SegmentMerge() and fts3AllocateSegdirIdx().
 */
-static int fts3SegmentMerge(Fts3Table *, int);
+static int fts3SegmentMerge(Fts3Table *, int, int);
 
 /* 
 ** This function allocates a new level iLevel index in the segdir table.
@@ -118399,7 +120519,12 @@ static int fts3SegmentMerge(Fts3Table *, int);
 ** If successful, *piIdx is set to the allocated index slot and SQLITE_OK
 ** returned. Otherwise, an SQLite error code is returned.
 */
-static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
+static int fts3AllocateSegdirIdx(
+  Fts3Table *p, 
+  int iIndex,                     /* Index for p->aIndex */
+  int iLevel, 
+  int *piIdx
+){
   int rc;                         /* Return Code */
   sqlite3_stmt *pNextIdx;         /* Query for next idx at level iLevel */
   int iNext = 0;                  /* Result of query pNextIdx */
@@ -118407,7 +120532,7 @@ static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
   /* Set variable iNext to the next available segdir index at level iLevel. */
   rc = fts3SqlStmt(p, SQL_NEXT_SEGMENT_INDEX, &pNextIdx, 0);
   if( rc==SQLITE_OK ){
-    sqlite3_bind_int(pNextIdx, 1, iLevel);
+    sqlite3_bind_int(pNextIdx, 1, iIndex*FTS3_SEGDIR_MAXLEVEL + iLevel);
     if( SQLITE_ROW==sqlite3_step(pNextIdx) ){
       iNext = sqlite3_column_int(pNextIdx, 0);
     }
@@ -118421,7 +120546,7 @@ static int fts3AllocateSegdirIdx(Fts3Table *p, int iLevel, int *piIdx){
     ** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
     */
     if( iNext>=FTS3_MERGE_COUNT ){
-      rc = fts3SegmentMerge(p, iLevel);
+      rc = fts3SegmentMerge(p, iIndex, iLevel);
       *piIdx = 0;
     }else{
       *piIdx = iNext;
@@ -118462,7 +120587,8 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
   Fts3Table *p,                   /* FTS3 table handle */
   sqlite3_int64 iBlockid,         /* Access the row with blockid=$iBlockid */
   char **paBlob,                  /* OUT: Blob data in malloc'd buffer */
-  int *pnBlob                     /* OUT: Size of blob data */
+  int *pnBlob,                    /* OUT: Size of blob data */
+  int *pnLoad                     /* OUT: Bytes actually loaded */
 ){
   int rc;                         /* Return code */
 
@@ -118483,11 +120609,16 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
 
   if( rc==SQLITE_OK ){
     int nByte = sqlite3_blob_bytes(p->pSegments);
+    *pnBlob = nByte;
     if( paBlob ){
       char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
       if( !aByte ){
         rc = SQLITE_NOMEM;
       }else{
+        if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){
+          nByte = FTS3_NODE_CHUNKSIZE;
+          *pnLoad = nByte;
+        }
         rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0);
         memset(&aByte[nByte], 0, FTS3_NODE_PADDING);
         if( rc!=SQLITE_OK ){
@@ -118497,7 +120628,6 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
       }
       *paBlob = aByte;
     }
-    *pnBlob = nByte;
   }
 
   return rc;
@@ -118511,13 +120641,55 @@ SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){
   sqlite3_blob_close(p->pSegments);
   p->pSegments = 0;
 }
+    
+static int fts3SegReaderIncrRead(Fts3SegReader *pReader){
+  int nRead;                      /* Number of bytes to read */
+  int rc;                         /* Return code */
+
+  nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE);
+  rc = sqlite3_blob_read(
+      pReader->pBlob, 
+      &pReader->aNode[pReader->nPopulate],
+      nRead,
+      pReader->nPopulate
+  );
+
+  if( rc==SQLITE_OK ){
+    pReader->nPopulate += nRead;
+    memset(&pReader->aNode[pReader->nPopulate], 0, FTS3_NODE_PADDING);
+    if( pReader->nPopulate==pReader->nNode ){
+      sqlite3_blob_close(pReader->pBlob);
+      pReader->pBlob = 0;
+      pReader->nPopulate = 0;
+    }
+  }
+  return rc;
+}
+
+static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
+  int rc = SQLITE_OK;
+  assert( !pReader->pBlob 
+       || (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode])
+  );
+  while( pReader->pBlob && rc==SQLITE_OK 
+     &&  (pFrom - pReader->aNode + nByte)>pReader->nPopulate
+  ){
+    rc = fts3SegReaderIncrRead(pReader);
+  }
+  return rc;
+}
 
 /*
 ** Move the iterator passed as the first argument to the next term in the
 ** segment. If successful, SQLITE_OK is returned. If there is no next term,
 ** SQLITE_DONE. Otherwise, an SQLite error code.
 */
-static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
+static int fts3SegReaderNext(
+  Fts3Table *p, 
+  Fts3SegReader *pReader,
+  int bIncr
+){
+  int rc;                         /* Return code of various sub-routines */
   char *pNext;                    /* Cursor variable */
   int nPrefix;                    /* Number of bytes in term prefix */
   int nSuffix;                    /* Number of bytes in term suffix */
@@ -118529,7 +120701,6 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
   }
 
   if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
-    int rc;                       /* Return code from Fts3ReadBlock() */
 
     if( fts3SegReaderIsPending(pReader) ){
       Fts3HashElem *pElem = *(pReader->ppNextElem);
@@ -118549,6 +120720,8 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
 
     if( !fts3SegReaderIsRootOnly(pReader) ){
       sqlite3_free(pReader->aNode);
+      sqlite3_blob_close(pReader->pBlob);
+      pReader->pBlob = 0;
     }
     pReader->aNode = 0;
 
@@ -118560,21 +120733,31 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
     }
 
     rc = sqlite3Fts3ReadBlock(
-        p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode
+        p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode, 
+        (bIncr ? &pReader->nPopulate : 0)
     );
     if( rc!=SQLITE_OK ) return rc;
+    assert( pReader->pBlob==0 );
+    if( bIncr && pReader->nPopulate<pReader->nNode ){
+      pReader->pBlob = p->pSegments;
+      p->pSegments = 0;
+    }
     pNext = pReader->aNode;
   }
+
+  assert( !fts3SegReaderIsPending(pReader) );
+
+  rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2);
+  if( rc!=SQLITE_OK ) return rc;
   
   /* Because of the FTS3_NODE_PADDING bytes of padding, the following is 
-  ** safe (no risk of overread) even if the node data is corrupted.  
-  */
+  ** safe (no risk of overread) even if the node data is corrupted. */
   pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix);
   pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix);
   if( nPrefix<0 || nSuffix<=0 
    || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] 
   ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_VTAB;
   }
 
   if( nPrefix+nSuffix>pReader->nTermAlloc ){
@@ -118586,6 +120769,10 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
     pReader->zTerm = zNew;
     pReader->nTermAlloc = nNew;
   }
+
+  rc = fts3SegReaderRequire(pReader, pNext, nSuffix+FTS3_VARINT_MAX);
+  if( rc!=SQLITE_OK ) return rc;
+
   memcpy(&pReader->zTerm[nPrefix], pNext, nSuffix);
   pReader->nTerm = nPrefix+nSuffix;
   pNext += nSuffix;
@@ -118598,9 +120785,9 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
   ** of these statements is untrue, then the data structure is corrupt.
   */
   if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] 
-   || pReader->aDoclist[pReader->nDoclist-1]
+   || (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
   ){
-    return SQLITE_CORRUPT;
+    return SQLITE_CORRUPT_VTAB;
   }
   return SQLITE_OK;
 }
@@ -118609,12 +120796,26 @@ static int fts3SegReaderNext(Fts3Table *p, Fts3SegReader *pReader){
 ** Set the SegReader to point to the first docid in the doclist associated
 ** with the current term.
 */
-static void fts3SegReaderFirstDocid(Fts3SegReader *pReader){
-  int n;
+static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){
+  int rc = SQLITE_OK;
   assert( pReader->aDoclist );
   assert( !pReader->pOffsetList );
-  n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid);
-  pReader->pOffsetList = &pReader->aDoclist[n];
+  if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){
+    u8 bEof = 0;
+    pReader->iDocid = 0;
+    pReader->nOffsetList = 0;
+    sqlite3Fts3DoclistPrev(0,
+        pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList, 
+        &pReader->iDocid, &pReader->nOffsetList, &bEof
+    );
+  }else{
+    rc = fts3SegReaderRequire(pReader, pReader->aDoclist, FTS3_VARINT_MAX);
+    if( rc==SQLITE_OK ){
+      int n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid);
+      pReader->pOffsetList = &pReader->aDoclist[n];
+    }
+  }
+  return rc;
 }
 
 /*
@@ -118627,128 +120828,125 @@ static void fts3SegReaderFirstDocid(Fts3SegReader *pReader){
 ** *pnOffsetList is set to the length of the set of column-offset
 ** lists, not including the nul-terminator byte. For example:
 */
-static void fts3SegReaderNextDocid(
-  Fts3SegReader *pReader,
-  char **ppOffsetList,
-  int *pnOffsetList
+static int fts3SegReaderNextDocid(
+  Fts3Table *pTab,
+  Fts3SegReader *pReader,         /* Reader to advance to next docid */
+  char **ppOffsetList,            /* OUT: Pointer to current position-list */
+  int *pnOffsetList               /* OUT: Length of *ppOffsetList in bytes */
 ){
+  int rc = SQLITE_OK;
   char *p = pReader->pOffsetList;
   char c = 0;
 
-  /* Pointer p currently points at the first byte of an offset list. The
-  ** following two lines advance it to point one byte past the end of
-  ** the same offset list.
-  */
-  while( *p | c ) c = *p++ & 0x80;
-  p++;
-
-  /* If required, populate the output variables with a pointer to and the
-  ** size of the previous offset-list.
-  */
-  if( ppOffsetList ){
-    *ppOffsetList = pReader->pOffsetList;
-    *pnOffsetList = (int)(p - pReader->pOffsetList - 1);
-  }
+  assert( p );
 
-  /* If there are no more entries in the doclist, set pOffsetList to
-  ** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and
-  ** Fts3SegReader.pOffsetList to point to the next offset list before
-  ** returning.
-  */
-  if( p>=&pReader->aDoclist[pReader->nDoclist] ){
-    pReader->pOffsetList = 0;
+  if( pTab->bDescIdx && fts3SegReaderIsPending(pReader) ){
+    /* A pending-terms seg-reader for an FTS4 table that uses order=desc.
+    ** Pending-terms doclists are always built up in ascending order, so
+    ** we have to iterate through them backwards here. */
+    u8 bEof = 0;
+    if( ppOffsetList ){
+      *ppOffsetList = pReader->pOffsetList;
+      *pnOffsetList = pReader->nOffsetList - 1;
+    }
+    sqlite3Fts3DoclistPrev(0,
+        pReader->aDoclist, pReader->nDoclist, &p, &pReader->iDocid,
+        &pReader->nOffsetList, &bEof
+    );
+    if( bEof ){
+      pReader->pOffsetList = 0;
+    }else{
+      pReader->pOffsetList = p;
+    }
   }else{
-    sqlite3_int64 iDelta;
-    pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
-    pReader->iDocid += iDelta;
-  }
-}
+    char *pEnd = &pReader->aDoclist[pReader->nDoclist];
 
-/*
-** This function is called to estimate the amount of data that will be 
-** loaded from the disk If SegReaderIterate() is called on this seg-reader,
-** in units of average document size.
-** 
-** This can be used as follows: If the caller has a small doclist that 
-** contains references to N documents, and is considering merging it with
-** a large doclist (size X "average documents"), it may opt not to load
-** the large doclist if X>N.
-*/
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCost(
-  Fts3Cursor *pCsr,               /* FTS3 cursor handle */
-  Fts3SegReader *pReader,         /* Segment-reader handle */
-  int *pnCost                     /* IN/OUT: Number of bytes read */
-){
-  Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
-  int rc = SQLITE_OK;             /* Return code */
-  int nCost = 0;                  /* Cost in bytes to return */
-  int pgsz = p->nPgsz;            /* Database page size */
-
-  /* If this seg-reader is reading the pending-terms table, or if all data
-  ** for the segment is stored on the root page of the b-tree, then the cost
-  ** is zero. In this case all required data is already in main memory.
-  */
-  if( p->bHasStat 
-   && !fts3SegReaderIsPending(pReader) 
-   && !fts3SegReaderIsRootOnly(pReader) 
-  ){
-    int nBlob = 0;
-    sqlite3_int64 iBlock;
-
-    if( pCsr->nRowAvg==0 ){
-      /* The average document size, which is required to calculate the cost
-      ** of each doclist, has not yet been determined. Read the required 
-      ** data from the %_stat table to calculate it.
-      **
-      ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3 
-      ** varints, where nCol is the number of columns in the FTS3 table.
-      ** The first varint is the number of documents currently stored in
-      ** the table. The following nCol varints contain the total amount of
-      ** data stored in all rows of each column of the table, from left
-      ** to right.
+    /* Pointer p currently points at the first byte of an offset list. The
+    ** following block advances it to point one byte past the end of
+    ** the same offset list. */
+    while( 1 ){
+  
+      /* The following line of code (and the "p++" below the while() loop) is
+      ** normally all that is required to move pointer p to the desired 
+      ** position. The exception is if this node is being loaded from disk
+      ** incrementally and pointer "p" now points to the first byte passed
+      ** the populated part of pReader->aNode[].
       */
-      sqlite3_stmt *pStmt;
-      sqlite3_int64 nDoc = 0;
-      sqlite3_int64 nByte = 0;
-      const char *pEnd;
-      const char *a;
-
-      rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
-      if( rc!=SQLITE_OK ) return rc;
-      a = sqlite3_column_blob(pStmt, 0);
-      assert( a );
-
-      pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
-      a += sqlite3Fts3GetVarint(a, &nDoc);
-      while( a<pEnd ){
-        a += sqlite3Fts3GetVarint(a, &nByte);
-      }
-      if( nDoc==0 || nByte==0 ){
-        sqlite3_reset(pStmt);
-        return SQLITE_CORRUPT;
-      }
-
-      pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz);
-      assert( pCsr->nRowAvg>0 ); 
-      rc = sqlite3_reset(pStmt);
+      while( *p | c ) c = *p++ & 0x80;
+      assert( *p==0 );
+  
+      if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break;
+      rc = fts3SegReaderIncrRead(pReader);
       if( rc!=SQLITE_OK ) return rc;
     }
+    p++;
+  
+    /* If required, populate the output variables with a pointer to and the
+    ** size of the previous offset-list.
+    */
+    if( ppOffsetList ){
+      *ppOffsetList = pReader->pOffsetList;
+      *pnOffsetList = (int)(p - pReader->pOffsetList - 1);
+    }
 
-    /* Assume that a blob flows over onto overflow pages if it is larger
-    ** than (pgsz-35) bytes in size (the file-format documentation
-    ** confirms this).
+    while( p<pEnd && *p==0 ) p++;
+  
+    /* If there are no more entries in the doclist, set pOffsetList to
+    ** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and
+    ** Fts3SegReader.pOffsetList to point to the next offset list before
+    ** returning.
     */
-    for(iBlock=pReader->iStartBlock; iBlock<=pReader->iLeafEndBlock; iBlock++){
-      rc = sqlite3Fts3ReadBlock(p, iBlock, 0, &nBlob);
-      if( rc!=SQLITE_OK ) break;
-      if( (nBlob+35)>pgsz ){
-        int nOvfl = (nBlob + 34)/pgsz;
-        nCost += ((nOvfl + pCsr->nRowAvg - 1)/pCsr->nRowAvg);
+    if( p>=pEnd ){
+      pReader->pOffsetList = 0;
+    }else{
+      rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
+      if( rc==SQLITE_OK ){
+        sqlite3_int64 iDelta;
+        pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
+        if( pTab->bDescIdx ){
+          pReader->iDocid -= iDelta;
+        }else{
+          pReader->iDocid += iDelta;
+        }
       }
     }
   }
 
-  *pnCost += nCost;
+  return SQLITE_OK;
+}
+
+
+SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
+  Fts3Cursor *pCsr, 
+  Fts3MultiSegReader *pMsr,
+  int *pnOvfl
+){
+  Fts3Table *p = (Fts3Table*)pCsr->base.pVtab;
+  int nOvfl = 0;
+  int ii;
+  int rc = SQLITE_OK;
+  int pgsz = p->nPgsz;
+
+  assert( p->bHasStat );
+  assert( pgsz>0 );
+
+  for(ii=0; rc==SQLITE_OK && ii<pMsr->nSegment; ii++){
+    Fts3SegReader *pReader = pMsr->apSegment[ii];
+    if( !fts3SegReaderIsPending(pReader) 
+     && !fts3SegReaderIsRootOnly(pReader) 
+    ){
+      sqlite3_int64 jj;
+      for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){
+        int nBlob;
+        rc = sqlite3Fts3ReadBlock(p, jj, 0, &nBlob, 0);
+        if( rc!=SQLITE_OK ) break;
+        if( (nBlob+35)>pgsz ){
+          nOvfl += (nBlob + 34)/pgsz;
+        }
+      }
+    }
+  }
+  *pnOvfl = nOvfl;
   return rc;
 }
 
@@ -118761,6 +120959,7 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
     sqlite3_free(pReader->zTerm);
     if( !fts3SegReaderIsRootOnly(pReader) ){
       sqlite3_free(pReader->aNode);
+      sqlite3_blob_close(pReader->pBlob);
     }
   }
   sqlite3_free(pReader);
@@ -118837,24 +121036,42 @@ static int fts3CompareElemByTerm(const void *lhs, const void *rhs){
 /*
 ** This function is used to allocate an Fts3SegReader that iterates through
 ** a subset of the terms stored in the Fts3Table.pendingTerms array.
+**
+** If the isPrefixIter parameter is zero, then the returned SegReader iterates
+** through each term in the pending-terms table. Or, if isPrefixIter is
+** non-zero, it iterates through each term and its prefixes. For example, if
+** the pending terms hash table contains the terms "sqlite", "mysql" and
+** "firebird", then the iterator visits the following 'terms' (in the order
+** shown):
+**
+**   f fi fir fire fireb firebi firebir firebird
+**   m my mys mysq mysql
+**   s sq sql sqli sqlit sqlite
+**
+** Whereas if isPrefixIter is zero, the terms visited are:
+**
+**   firebird mysql sqlite
 */
 SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
   Fts3Table *p,                   /* Virtual table handle */
+  int iIndex,                     /* Index for p->aIndex */
   const char *zTerm,              /* Term to search for */
   int nTerm,                      /* Size of buffer zTerm */
-  int isPrefix,                   /* True for a term-prefix query */
+  int bPrefix,                    /* True for a prefix iterator */
   Fts3SegReader **ppReader        /* OUT: SegReader for pending-terms */
 ){
   Fts3SegReader *pReader = 0;     /* Fts3SegReader object to return */
   Fts3HashElem **aElem = 0;       /* Array of term hash entries to scan */
   int nElem = 0;                  /* Size of array at aElem */
   int rc = SQLITE_OK;             /* Return Code */
+  Fts3Hash *pHash;
 
-  if( isPrefix ){
+  pHash = &p->aIndex[iIndex].hPending;
+  if( bPrefix ){
     int nAlloc = 0;               /* Size of allocated array at aElem */
     Fts3HashElem *pE = 0;         /* Iterator variable */
 
-    for(pE=fts3HashFirst(&p->pendingTerms); pE; pE=fts3HashNext(pE)){
+    for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){
       char *zKey = (char *)fts3HashKey(pE);
       int nKey = fts3HashKeysize(pE);
       if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){
@@ -118871,6 +121088,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
           }
           aElem = aElem2;
         }
+
         aElem[nElem++] = pE;
       }
     }
@@ -118884,7 +121102,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
     }
 
   }else{
-    Fts3HashElem *pE = fts3HashFindElem(&p->pendingTerms, zTerm, nTerm);
+    /* The query is a simple term lookup that matches at most one term in
+    ** the index. All that is required is a straight hash-lookup. */
+    Fts3HashElem *pE = fts3HashFindElem(pHash, zTerm, nTerm);
     if( pE ){
       aElem = &pE;
       nElem = 1;
@@ -118904,7 +121124,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
     }
   }
 
-  if( isPrefix ){
+  if( bPrefix ){
     sqlite3_free(aElem);
   }
   *ppReader = pReader;
@@ -118968,6 +121188,18 @@ static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
   assert( pLhs->aNode && pRhs->aNode );
   return rc;
 }
+static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
+  int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0);
+  if( rc==0 ){
+    if( pLhs->iDocid==pRhs->iDocid ){
+      rc = pRhs->iIdx - pLhs->iIdx;
+    }else{
+      rc = (pLhs->iDocid < pRhs->iDocid) ? 1 : -1;
+    }
+  }
+  assert( pLhs->aNode && pRhs->aNode );
+  return rc;
+}
 
 /*
 ** Compare the term that the Fts3SegReader object passed as the first argument
@@ -119496,16 +121728,16 @@ static void fts3SegWriterFree(SegmentWriter *pWriter){
 ** The first value in the apVal[] array is assumed to contain an integer.
 ** This function tests if there exist any documents with docid values that
 ** are different from that integer. i.e. if deleting the document with docid
-** apVal[0] would mean the FTS3 table were empty.
+** pRowid would mean the FTS3 table were empty.
 **
 ** If successful, *pisEmpty is set to true if the table is empty except for
-** document apVal[0], or false otherwise, and SQLITE_OK is returned. If an
+** document pRowid, or false otherwise, and SQLITE_OK is returned. If an
 ** error occurs, an SQLite error code is returned.
 */
-static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){
+static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
   sqlite3_stmt *pStmt;
   int rc;
-  rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, apVal);
+  rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
   if( rc==SQLITE_OK ){
     if( SQLITE_ROW==sqlite3_step(pStmt) ){
       *pisEmpty = sqlite3_column_int(pStmt, 0);
@@ -119516,21 +121748,30 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){
 }
 
 /*
-** Set *pnSegment to the total number of segments in the database. Set
-** *pnMax to the largest segment level in the database (segment levels
-** are stored in the 'level' column of the %_segdir table).
+** Set *pnMax to the largest segment level in the database for the index
+** iIndex.
+**
+** Segment levels are stored in the 'level' column of the %_segdir table.
 **
 ** Return SQLITE_OK if successful, or an SQLite error code if not.
 */
-static int fts3SegmentCountMax(Fts3Table *p, int *pnSegment, int *pnMax){
+static int fts3SegmentMaxLevel(Fts3Table *p, int iIndex, int *pnMax){
   sqlite3_stmt *pStmt;
   int rc;
+  assert( iIndex>=0 && iIndex<p->nIndex );
 
-  rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_COUNT_MAX, &pStmt, 0);
+  /* Set pStmt to the compiled version of:
+  **
+  **   SELECT max(level) FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ?
+  **
+  ** (1024 is actually the value of macro FTS3_SEGDIR_PREFIXLEVEL_STR).
+  */
+  rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
   if( rc!=SQLITE_OK ) return rc;
+  sqlite3_bind_int(pStmt, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
+  sqlite3_bind_int(pStmt, 2, (iIndex+1)*FTS3_SEGDIR_MAXLEVEL - 1);
   if( SQLITE_ROW==sqlite3_step(pStmt) ){
-    *pnSegment = sqlite3_column_int(pStmt, 0);
-    *pnMax = sqlite3_column_int(pStmt, 1);
+    *pnMax = sqlite3_column_int(pStmt, 0);
   }
   return sqlite3_reset(pStmt);
 }
@@ -119551,6 +121792,7 @@ static int fts3SegmentCountMax(Fts3Table *p, int *pnSegment, int *pnMax){
 */
 static int fts3DeleteSegdir(
   Fts3Table *p,                   /* Virtual table handle */
+  int iIndex,                     /* Index for p->aIndex */
   int iLevel,                     /* Level of %_segdir entries to delete */
   Fts3SegReader **apSegment,      /* Array of SegReader objects */
   int nReader                     /* Size of array apSegment */
@@ -119573,20 +121815,25 @@ static int fts3DeleteSegdir(
     return rc;
   }
 
+  assert( iLevel>=0 || iLevel==FTS3_SEGCURSOR_ALL );
   if( iLevel==FTS3_SEGCURSOR_ALL ){
-    fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
-  }else if( iLevel==FTS3_SEGCURSOR_PENDING ){
-    sqlite3Fts3PendingTermsClear(p);
+    rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int(pDelete, 1, iIndex*FTS3_SEGDIR_MAXLEVEL);
+      sqlite3_bind_int(pDelete, 2, (iIndex+1) * FTS3_SEGDIR_MAXLEVEL - 1);
+    }
   }else{
-    assert( iLevel>=0 );
-    rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_BY_LEVEL, &pDelete, 0);
+    rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pDelete, 0);
     if( rc==SQLITE_OK ){
-      sqlite3_bind_int(pDelete, 1, iLevel);
-      sqlite3_step(pDelete);
-      rc = sqlite3_reset(pDelete);
+      sqlite3_bind_int(pDelete, 1, iIndex*FTS3_SEGDIR_MAXLEVEL + iLevel);
     }
   }
 
+  if( rc==SQLITE_OK ){
+    sqlite3_step(pDelete);
+    rc = sqlite3_reset(pDelete);
+  }
+
   return rc;
 }
 
@@ -119633,15 +121880,106 @@ static void fts3ColumnFilter(
   *pnList = nList;
 }
 
-SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(
+/*
+** Cache data in the Fts3MultiSegReader.aBuffer[] buffer (overwriting any
+** existing data). Grow the buffer if required.
+**
+** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered
+** trying to resize the buffer, return SQLITE_NOMEM.
+*/
+static int fts3MsrBufferData(
+  Fts3MultiSegReader *pMsr,       /* Multi-segment-reader handle */
+  char *pList,
+  int nList
+){
+  if( nList>pMsr->nBuffer ){
+    char *pNew;
+    pMsr->nBuffer = nList*2;
+    pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer);
+    if( !pNew ) return SQLITE_NOMEM;
+    pMsr->aBuffer = pNew;
+  }
+
+  memcpy(pMsr->aBuffer, pList, nList);
+  return SQLITE_OK;
+}
+
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
   Fts3Table *p,                   /* Virtual table handle */
-  Fts3SegReaderCursor *pCsr,      /* Cursor object */
-  Fts3SegFilter *pFilter          /* Restrictions on range of iteration */
+  Fts3MultiSegReader *pMsr,       /* Multi-segment-reader handle */
+  sqlite3_int64 *piDocid,         /* OUT: Docid value */
+  char **paPoslist,               /* OUT: Pointer to position list */
+  int *pnPoslist                  /* OUT: Size of position list in bytes */
+){
+  int nMerge = pMsr->nAdvance;
+  Fts3SegReader **apSegment = pMsr->apSegment;
+  int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
+    p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp
+  );
+
+  if( nMerge==0 ){
+    *paPoslist = 0;
+    return SQLITE_OK;
+  }
+
+  while( 1 ){
+    Fts3SegReader *pSeg;
+    pSeg = pMsr->apSegment[0];
+
+    if( pSeg->pOffsetList==0 ){
+      *paPoslist = 0;
+      break;
+    }else{
+      int rc;
+      char *pList;
+      int nList;
+      int j;
+      sqlite3_int64 iDocid = apSegment[0]->iDocid;
+
+      rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
+      j = 1;
+      while( rc==SQLITE_OK 
+        && j<nMerge
+        && apSegment[j]->pOffsetList
+        && apSegment[j]->iDocid==iDocid
+      ){
+        rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0);
+        j++;
+      }
+      if( rc!=SQLITE_OK ) return rc;
+      fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
+
+      if( pMsr->iColFilter>=0 ){
+        fts3ColumnFilter(pMsr->iColFilter, &pList, &nList);
+      }
+
+      if( nList>0 ){
+        if( fts3SegReaderIsPending(apSegment[0]) ){
+          rc = fts3MsrBufferData(pMsr, pList, nList+1);
+          if( rc!=SQLITE_OK ) return rc;
+          *paPoslist = pMsr->aBuffer;
+          assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
+        }else{
+          *paPoslist = pList;
+        }
+        *piDocid = iDocid;
+        *pnPoslist = nList;
+        break;
+      }
+    }
+  }
+
+  return SQLITE_OK;
+}
+
+static int fts3SegReaderStart(
+  Fts3Table *p,                   /* Virtual table handle */
+  Fts3MultiSegReader *pCsr,       /* Cursor object */
+  const char *zTerm,              /* Term searched for (or NULL) */
+  int nTerm                       /* Length of zTerm in bytes */
 ){
   int i;
-
-  /* Initialize the cursor object */
-  pCsr->pFilter = pFilter;
+  int nSeg = pCsr->nSegment;
 
   /* If the Fts3SegFilter defines a specific term (or term prefix) to search 
   ** for, then advance each segment iterator until it points to a term of
@@ -119649,24 +121987,105 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(
   ** unnecessary merge/sort operations for the case where single segment
   ** b-tree leaf nodes contain more than one term.
   */
-  for(i=0; i<pCsr->nSegment; i++){
-    int nTerm = pFilter->nTerm;
-    const char *zTerm = pFilter->zTerm;
+  for(i=0; pCsr->bRestart==0 && i<pCsr->nSegment; i++){
     Fts3SegReader *pSeg = pCsr->apSegment[i];
     do {
-      int rc = fts3SegReaderNext(p, pSeg);
+      int rc = fts3SegReaderNext(p, pSeg, 0);
       if( rc!=SQLITE_OK ) return rc;
     }while( zTerm && fts3SegReaderTermCmp(pSeg, zTerm, nTerm)<0 );
   }
-  fts3SegReaderSort(
-      pCsr->apSegment, pCsr->nSegment, pCsr->nSegment, fts3SegReaderCmp);
+  fts3SegReaderSort(pCsr->apSegment, nSeg, nSeg, fts3SegReaderCmp);
 
   return SQLITE_OK;
 }
 
+SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(
+  Fts3Table *p,                   /* Virtual table handle */
+  Fts3MultiSegReader *pCsr,       /* Cursor object */
+  Fts3SegFilter *pFilter          /* Restrictions on range of iteration */
+){
+  pCsr->pFilter = pFilter;
+  return fts3SegReaderStart(p, pCsr, pFilter->zTerm, pFilter->nTerm);
+}
+
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
+  Fts3Table *p,                   /* Virtual table handle */
+  Fts3MultiSegReader *pCsr,       /* Cursor object */
+  int iCol,                       /* Column to match on. */
+  const char *zTerm,              /* Term to iterate through a doclist for */
+  int nTerm                       /* Number of bytes in zTerm */
+){
+  int i;
+  int rc;
+  int nSegment = pCsr->nSegment;
+  int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
+    p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp
+  );
+
+  assert( pCsr->pFilter==0 );
+  assert( zTerm && nTerm>0 );
+
+  /* Advance each segment iterator until it points to the term zTerm/nTerm. */
+  rc = fts3SegReaderStart(p, pCsr, zTerm, nTerm);
+  if( rc!=SQLITE_OK ) return rc;
+
+  /* Determine how many of the segments actually point to zTerm/nTerm. */
+  for(i=0; i<nSegment; i++){
+    Fts3SegReader *pSeg = pCsr->apSegment[i];
+    if( !pSeg->aNode || fts3SegReaderTermCmp(pSeg, zTerm, nTerm) ){
+      break;
+    }
+  }
+  pCsr->nAdvance = i;
+
+  /* Advance each of the segments to point to the first docid. */
+  for(i=0; i<pCsr->nAdvance; i++){
+    rc = fts3SegReaderFirstDocid(p, pCsr->apSegment[i]);
+    if( rc!=SQLITE_OK ) return rc;
+  }
+  fts3SegReaderSort(pCsr->apSegment, i, i, xCmp);
+
+  assert( iCol<0 || iCol<p->nColumn );
+  pCsr->iColFilter = iCol;
+
+  return SQLITE_OK;
+}
+
+/*
+** This function is called on a MultiSegReader that has been started using
+** sqlite3Fts3MsrIncrStart(). One or more calls to MsrIncrNext() may also
+** have been made. Calling this function puts the MultiSegReader in such
+** a state that if the next two calls are:
+**
+**   sqlite3Fts3SegReaderStart()
+**   sqlite3Fts3SegReaderStep()
+**
+** then the entire doclist for the term is available in 
+** MultiSegReader.aDoclist/nDoclist.
+*/
+SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
+  int i;                          /* Used to iterate through segment-readers */
+
+  assert( pCsr->zTerm==0 );
+  assert( pCsr->nTerm==0 );
+  assert( pCsr->aDoclist==0 );
+  assert( pCsr->nDoclist==0 );
+
+  pCsr->nAdvance = 0;
+  pCsr->bRestart = 1;
+  for(i=0; i<pCsr->nSegment; i++){
+    pCsr->apSegment[i]->pOffsetList = 0;
+    pCsr->apSegment[i]->nOffsetList = 0;
+    pCsr->apSegment[i]->iDocid = 0;
+  }
+
+  return SQLITE_OK;
+}
+
+
 SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
   Fts3Table *p,                   /* Virtual table handle */
-  Fts3SegReaderCursor *pCsr       /* Cursor object */
+  Fts3MultiSegReader *pCsr        /* Cursor object */
 ){
   int rc = SQLITE_OK;
 
@@ -119679,6 +122098,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
   Fts3SegReader **apSegment = pCsr->apSegment;
   int nSegment = pCsr->nSegment;
   Fts3SegFilter *pFilter = pCsr->pFilter;
+  int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
+    p->bDescIdx ? fts3SegReaderDoclistCmpRev : fts3SegReaderDoclistCmp
+  );
 
   if( pCsr->nSegment==0 ) return SQLITE_OK;
 
@@ -119690,7 +122112,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
     ** forward. Then sort the list in order of current term again.  
     */
     for(i=0; i<pCsr->nAdvance; i++){
-      rc = fts3SegReaderNext(p, apSegment[i]);
+      rc = fts3SegReaderNext(p, apSegment[i], 0);
       if( rc!=SQLITE_OK ) return rc;
     }
     fts3SegReaderSort(apSegment, nSegment, pCsr->nAdvance, fts3SegReaderCmp);
@@ -119729,10 +122151,18 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
     }
 
     assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
-    if( nMerge==1 && !isIgnoreEmpty ){
-      pCsr->aDoclist = apSegment[0]->aDoclist;
+    if( nMerge==1 
+     && !isIgnoreEmpty 
+     && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
+    ){
       pCsr->nDoclist = apSegment[0]->nDoclist;
-      rc = SQLITE_ROW;
+      if( fts3SegReaderIsPending(apSegment[0]) ){
+        rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
+        pCsr->aDoclist = pCsr->aBuffer;
+      }else{
+        pCsr->aDoclist = apSegment[0]->aDoclist;
+      }
+      if( rc==SQLITE_OK ) rc = SQLITE_ROW;
     }else{
       int nDoclist = 0;           /* Size of doclist */
       sqlite3_int64 iPrev = 0;    /* Previous docid stored in doclist */
@@ -119742,22 +122172,22 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
       ** and a single term returned with the merged doclist.
       */
       for(i=0; i<nMerge; i++){
-        fts3SegReaderFirstDocid(apSegment[i]);
+        fts3SegReaderFirstDocid(p, apSegment[i]);
       }
-      fts3SegReaderSort(apSegment, nMerge, nMerge, fts3SegReaderDoclistCmp);
+      fts3SegReaderSort(apSegment, nMerge, nMerge, xCmp);
       while( apSegment[0]->pOffsetList ){
         int j;                    /* Number of segments that share a docid */
         char *pList;
         int nList;
         int nByte;
         sqlite3_int64 iDocid = apSegment[0]->iDocid;
-        fts3SegReaderNextDocid(apSegment[0], &pList, &nList);
+        fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
         j = 1;
         while( j<nMerge
             && apSegment[j]->pOffsetList
             && apSegment[j]->iDocid==iDocid
         ){
-          fts3SegReaderNextDocid(apSegment[j], 0, 0);
+          fts3SegReaderNextDocid(p, apSegment[j], 0, 0);
           j++;
         }
 
@@ -119766,7 +122196,19 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
         }
 
         if( !isIgnoreEmpty || nList>0 ){
-          nByte = sqlite3Fts3VarintLen(iDocid-iPrev) + (isRequirePos?nList+1:0);
+
+          /* Calculate the 'docid' delta value to write into the merged 
+          ** doclist. */
+          sqlite3_int64 iDelta;
+          if( p->bDescIdx && nDoclist>0 ){
+            iDelta = iPrev - iDocid;
+          }else{
+            iDelta = iDocid - iPrev;
+          }
+          assert( iDelta>0 || (nDoclist==0 && iDelta==iDocid) );
+          assert( nDoclist>0 || iDelta==iDocid );
+
+          nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
           if( nDoclist+nByte>pCsr->nBuffer ){
             char *aNew;
             pCsr->nBuffer = (nDoclist+nByte)*2;
@@ -119776,9 +122218,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
             }
             pCsr->aBuffer = aNew;
           }
-          nDoclist += sqlite3Fts3PutVarint(
-              &pCsr->aBuffer[nDoclist], iDocid-iPrev
-          );
+          nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
           iPrev = iDocid;
           if( isRequirePos ){
             memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
@@ -119787,7 +122227,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
           }
         }
 
-        fts3SegReaderSort(apSegment, nMerge, j, fts3SegReaderDoclistCmp);
+        fts3SegReaderSort(apSegment, nMerge, j, xCmp);
       }
       if( nDoclist>0 ){
         pCsr->aDoclist = pCsr->aBuffer;
@@ -119801,8 +122241,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
   return rc;
 }
 
+
 SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
-  Fts3SegReaderCursor *pCsr       /* Cursor object */
+  Fts3MultiSegReader *pCsr       /* Cursor object */
 ){
   if( pCsr ){
     int i;
@@ -119829,43 +122270,56 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
 ** Otherwise, if successful, SQLITE_OK is returned. If an error occurs, 
 ** an SQLite error code is returned.
 */
-static int fts3SegmentMerge(Fts3Table *p, int iLevel){
+static int fts3SegmentMerge(Fts3Table *p, int iIndex, int iLevel){
   int rc;                         /* Return code */
   int iIdx = 0;                   /* Index of new segment */
-  int iNewLevel = 0;              /* Level to create new segment at */
+  int iNewLevel = 0;              /* Level/index to create new segment at */
   SegmentWriter *pWriter = 0;     /* Used to write the new, merged, segment */
   Fts3SegFilter filter;           /* Segment term filter condition */
-  Fts3SegReaderCursor csr;        /* Cursor to iterate through level(s) */
+  Fts3MultiSegReader csr;        /* Cursor to iterate through level(s) */
+  int bIgnoreEmpty = 0;           /* True to ignore empty segments */
 
-  rc = sqlite3Fts3SegReaderCursor(p, iLevel, 0, 0, 1, 0, &csr);
+  assert( iLevel==FTS3_SEGCURSOR_ALL
+       || iLevel==FTS3_SEGCURSOR_PENDING
+       || iLevel>=0
+  );
+  assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
+  assert( iIndex>=0 && iIndex<p->nIndex );
+
+  rc = sqlite3Fts3SegReaderCursor(p, iIndex, iLevel, 0, 0, 1, 0, &csr);
   if( rc!=SQLITE_OK || csr.nSegment==0 ) goto finished;
 
   if( iLevel==FTS3_SEGCURSOR_ALL ){
     /* This call is to merge all segments in the database to a single
     ** segment. The level of the new segment is equal to the the numerically 
-    ** greatest segment level currently present in the database. The index
-    ** of the new segment is always 0.  */
-    int nDummy; /* TODO: Remove this */
+    ** greatest segment level currently present in the database for this
+    ** index. The idx of the new segment is always 0.  */
     if( csr.nSegment==1 ){
       rc = SQLITE_DONE;
       goto finished;
     }
-    rc = fts3SegmentCountMax(p, &nDummy, &iNewLevel);
+    rc = fts3SegmentMaxLevel(p, iIndex, &iNewLevel);
+    bIgnoreEmpty = 1;
+
+  }else if( iLevel==FTS3_SEGCURSOR_PENDING ){
+    iNewLevel = iIndex * FTS3_SEGDIR_MAXLEVEL; 
+    rc = fts3AllocateSegdirIdx(p, iIndex, 0, &iIdx);
   }else{
-    /* This call is to merge all segments at level iLevel. Find the next
+    /* This call is to merge all segments at level iLevel. find the next
     ** available segment index at level iLevel+1. The call to
     ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to 
     ** a single iLevel+2 segment if necessary.  */
-    iNewLevel = iLevel+1;
-    rc = fts3AllocateSegdirIdx(p, iNewLevel, &iIdx);
+    rc = fts3AllocateSegdirIdx(p, iIndex, iLevel+1, &iIdx);
+    iNewLevel = iIndex * FTS3_SEGDIR_MAXLEVEL + iLevel+1;
   }
   if( rc!=SQLITE_OK ) goto finished;
   assert( csr.nSegment>0 );
-  assert( iNewLevel>=0 );
+  assert( iNewLevel>=(iIndex*FTS3_SEGDIR_MAXLEVEL) );
+  assert( iNewLevel<((iIndex+1)*FTS3_SEGDIR_MAXLEVEL) );
 
   memset(&filter, 0, sizeof(Fts3SegFilter));
   filter.flags = FTS3_SEGMENT_REQUIRE_POS;
-  filter.flags |= (iLevel==FTS3_SEGCURSOR_ALL ? FTS3_SEGMENT_IGNORE_EMPTY : 0);
+  filter.flags |= (bIgnoreEmpty ? FTS3_SEGMENT_IGNORE_EMPTY : 0);
 
   rc = sqlite3Fts3SegReaderStart(p, &csr, &filter);
   while( SQLITE_OK==rc ){
@@ -119877,8 +122331,10 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
   if( rc!=SQLITE_OK ) goto finished;
   assert( pWriter );
 
-  rc = fts3DeleteSegdir(p, iLevel, csr.apSegment, csr.nSegment);
-  if( rc!=SQLITE_OK ) goto finished;
+  if( iLevel!=FTS3_SEGCURSOR_PENDING ){
+    rc = fts3DeleteSegdir(p, iIndex, iLevel, csr.apSegment, csr.nSegment);
+    if( rc!=SQLITE_OK ) goto finished;
+  }
   rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
 
  finished:
@@ -119889,10 +122345,17 @@ static int fts3SegmentMerge(Fts3Table *p, int iLevel){
 
 
 /* 
-** Flush the contents of pendingTerms to a level 0 segment.
+** Flush the contents of pendingTerms to level 0 segments.
 */
 SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
-  return fts3SegmentMerge(p, FTS3_SEGCURSOR_PENDING);
+  int rc = SQLITE_OK;
+  int i;
+  for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
+    rc = fts3SegmentMerge(p, i, FTS3_SEGCURSOR_PENDING);
+    if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+  }
+  sqlite3Fts3PendingTermsClear(p);
+  return rc;
 }
 
 /*
@@ -120043,6 +122506,23 @@ static void fts3UpdateDocTotals(
   sqlite3_free(a);
 }
 
+static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
+  int i;
+  int bSeenDone = 0;
+  int rc = SQLITE_OK;
+  for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
+    rc = fts3SegmentMerge(p, i, FTS3_SEGCURSOR_ALL);
+    if( rc==SQLITE_DONE ){
+      bSeenDone = 1;
+      rc = SQLITE_OK;
+    }
+  }
+  sqlite3Fts3SegmentsClose(p);
+  sqlite3Fts3PendingTermsClear(p);
+
+  return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
+}
+
 /*
 ** Handle a 'special' INSERT of the form:
 **
@@ -120059,12 +122539,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
   if( !zVal ){
     return SQLITE_NOMEM;
   }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
-    rc = fts3SegmentMerge(p, FTS3_SEGCURSOR_ALL);
-    if( rc==SQLITE_DONE ){
-      rc = SQLITE_OK;
-    }else{
-      sqlite3Fts3PendingTermsClear(p);
-    }
+    rc = fts3DoOptimize(p, 0);
 #ifdef SQLITE_TEST
   }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
     p->nNodeSize = atoi(&zVal[9]);
@@ -120077,44 +122552,9 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
     rc = SQLITE_ERROR;
   }
 
-  sqlite3Fts3SegmentsClose(p);
   return rc;
 }
 
-/*
-** Return the deferred doclist associated with deferred token pDeferred.
-** This function assumes that sqlite3Fts3CacheDeferredDoclists() has already
-** been called to allocate and populate the doclist.
-*/
-SQLITE_PRIVATE char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *pDeferred, int *pnByte){
-  if( pDeferred->pList ){
-    *pnByte = pDeferred->pList->nData;
-    return pDeferred->pList->aData;
-  }
-  *pnByte = 0;
-  return 0;
-}
-
-/*
-** Helper fucntion for FreeDeferredDoclists(). This function removes all
-** references to deferred doclists from within the tree of Fts3Expr 
-** structures headed by 
-*/
-static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
-  if( pExpr ){
-    fts3DeferredDoclistClear(pExpr->pLeft);
-    fts3DeferredDoclistClear(pExpr->pRight);
-    if( pExpr->isLoaded ){
-      sqlite3_free(pExpr->aDoclist);
-      pExpr->isLoaded = 0;
-      pExpr->aDoclist = 0;
-      pExpr->nDoclist = 0;
-      pExpr->pCurrent = 0;
-      pExpr->iCurrent = 0;
-    }
-  }
-}
-
 /*
 ** Delete all cached deferred doclists. Deferred doclists are cached
 ** (allocated) by the sqlite3Fts3CacheDeferredDoclists() function.
@@ -120122,12 +122562,9 @@ static void fts3DeferredDoclistClear(Fts3Expr *pExpr){
 SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
   Fts3DeferredToken *pDef;
   for(pDef=pCsr->pDeferred; pDef; pDef=pDef->pNext){
-    sqlite3_free(pDef->pList);
+    fts3PendingListDelete(pDef->pList);
     pDef->pList = 0;
   }
-  if( pCsr->pDeferred ){
-    fts3DeferredDoclistClear(pCsr->pExpr);
-  }
 }
 
 /*
@@ -120139,7 +122576,7 @@ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
   Fts3DeferredToken *pNext;
   for(pDef=pCsr->pDeferred; pDef; pDef=pNext){
     pNext = pDef->pNext;
-    sqlite3_free(pDef->pList);
+    fts3PendingListDelete(pDef->pList);
     sqlite3_free(pDef);
   }
   pCsr->pDeferred = 0;
@@ -120204,6 +122641,33 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
   return rc;
 }
 
+SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
+  Fts3DeferredToken *p, 
+  char **ppData, 
+  int *pnData
+){
+  char *pRet;
+  int nSkip;
+  sqlite3_int64 dummy;
+
+  *ppData = 0;
+  *pnData = 0;
+
+  if( p->pList==0 ){
+    return SQLITE_OK;
+  }
+
+  pRet = (char *)sqlite3_malloc(p->pList->nData);
+  if( !pRet ) return SQLITE_NOMEM;
+
+  nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
+  *pnData = p->pList->nData - nSkip;
+  *ppData = pRet;
+  
+  memcpy(pRet, &p->pList->aData[nSkip], *pnData);
+  return SQLITE_OK;
+}
+
 /*
 ** Add an entry for token pToken to the pCsr->pDeferred list.
 */
@@ -120229,6 +122693,40 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
   return SQLITE_OK;
 }
 
+/*
+** SQLite value pRowid contains the rowid of a row that may or may not be
+** present in the FTS3 table. If it is, delete it and adjust the contents
+** of subsiduary data structures accordingly.
+*/
+static int fts3DeleteByRowid(
+  Fts3Table *p, 
+  sqlite3_value *pRowid, 
+  int *pnDoc,
+  u32 *aSzDel
+){
+  int isEmpty = 0;
+  int rc = fts3IsEmpty(p, pRowid, &isEmpty);
+  if( rc==SQLITE_OK ){
+    if( isEmpty ){
+      /* Deleting this row means the whole table is empty. In this case
+      ** delete the contents of all three tables and throw away any
+      ** data in the pendingTerms hash table.  */
+      rc = fts3DeleteAll(p);
+      *pnDoc = *pnDoc - 1;
+    }else{
+      sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
+      rc = fts3PendingTermsDocid(p, iRemove);
+      fts3DeleteTerms(&rc, p, pRowid, aSzDel);
+      fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
+      if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
+      if( p->bHasDocsize ){
+        fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
+      }
+    }
+  }
+
+  return rc;
+}
 
 /*
 ** This function does the work for the xUpdate method of FTS3 virtual
@@ -120244,49 +122742,97 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
   int rc = SQLITE_OK;             /* Return Code */
   int isRemove = 0;               /* True for an UPDATE or DELETE */
   sqlite3_int64 iRemove = 0;      /* Rowid removed by UPDATE or DELETE */
-  u32 *aSzIns;                    /* Sizes of inserted documents */
+  u32 *aSzIns = 0;                /* Sizes of inserted documents */
   u32 *aSzDel;                    /* Sizes of deleted documents */
   int nChng = 0;                  /* Net change in number of documents */
+  int bInsertDone = 0;
 
   assert( p->pSegments==0 );
 
+  /* Check for a "special" INSERT operation. One of the form:
+  **
+  **   INSERT INTO xyz(xyz) VALUES('command');
+  */
+  if( nArg>1 
+   && sqlite3_value_type(apVal[0])==SQLITE_NULL 
+   && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL 
+  ){
+    rc = fts3SpecialInsert(p, apVal[p->nColumn+2]);
+    goto update_out;
+  }
+
   /* Allocate space to hold the change in document sizes */
   aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 );
-  if( aSzIns==0 ) return SQLITE_NOMEM;
+  if( aSzIns==0 ){
+    rc = SQLITE_NOMEM;
+    goto update_out;
+  }
   aSzDel = &aSzIns[p->nColumn+1];
   memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2);
 
-  /* If this is a DELETE or UPDATE operation, remove the old record. */
-  if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
-    int isEmpty = 0;
-    rc = fts3IsEmpty(p, apVal, &isEmpty);
-    if( rc==SQLITE_OK ){
-      if( isEmpty ){
-        /* Deleting this row means the whole table is empty. In this case
-        ** delete the contents of all three tables and throw away any
-        ** data in the pendingTerms hash table.
-        */
-        rc = fts3DeleteAll(p);
+  /* If this is an INSERT operation, or an UPDATE that modifies the rowid
+  ** value, then this operation requires constraint handling.
+  **
+  ** If the on-conflict mode is REPLACE, this means that the existing row
+  ** should be deleted from the database before inserting the new row. Or,
+  ** if the on-conflict mode is other than REPLACE, then this method must
+  ** detect the conflict and return SQLITE_CONSTRAINT before beginning to
+  ** modify the database file.
+  */
+  if( nArg>1 ){
+    /* Find the value object that holds the new rowid value. */
+    sqlite3_value *pNewRowid = apVal[3+p->nColumn];
+    if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){
+      pNewRowid = apVal[1];
+    }
+
+    if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( 
+        sqlite3_value_type(apVal[0])==SQLITE_NULL
+     || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid)
+    )){
+      /* The new rowid is not NULL (in this case the rowid will be
+      ** automatically assigned and there is no chance of a conflict), and 
+      ** the statement is either an INSERT or an UPDATE that modifies the
+      ** rowid column. So if the conflict mode is REPLACE, then delete any
+      ** existing row with rowid=pNewRowid. 
+      **
+      ** Or, if the conflict mode is not REPLACE, insert the new record into 
+      ** the %_content table. If we hit the duplicate rowid constraint (or any
+      ** other error) while doing so, return immediately.
+      **
+      ** This branch may also run if pNewRowid contains a value that cannot
+      ** be losslessly converted to an integer. In this case, the eventual 
+      ** call to fts3InsertData() (either just below or further on in this
+      ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is 
+      ** invoked, it will delete zero rows (since no row will have
+      ** docid=$pNewRowid if $pNewRowid is not an integer value).
+      */
+      if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){
+        rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel);
       }else{
-        isRemove = 1;
-        iRemove = sqlite3_value_int64(apVal[0]);
-        rc = fts3PendingTermsDocid(p, iRemove);
-        fts3DeleteTerms(&rc, p, apVal, aSzDel);
-        fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal);
-        if( p->bHasDocsize ){
-          fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal);
-        }
-        nChng--;
+        rc = fts3InsertData(p, apVal, pRowid);
+        bInsertDone = 1;
       }
     }
-  }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){
-    sqlite3_free(aSzIns);
-    return fts3SpecialInsert(p, apVal[p->nColumn+2]);
+  }
+  if( rc!=SQLITE_OK ){
+    goto update_out;
+  }
+
+  /* If this is a DELETE or UPDATE operation, remove the old record. */
+  if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
+    assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
+    rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
+    isRemove = 1;
+    iRemove = sqlite3_value_int64(apVal[0]);
   }
   
   /* If this is an INSERT or UPDATE operation, insert the new record. */
   if( nArg>1 && rc==SQLITE_OK ){
-    rc = fts3InsertData(p, apVal, pRowid);
+    if( bInsertDone==0 ){
+      rc = fts3InsertData(p, apVal, pRowid);
+      if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB;
+    }
     if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){
       rc = fts3PendingTermsDocid(p, *pRowid);
     }
@@ -120303,6 +122849,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
     fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
   }
 
+ update_out:
   sqlite3_free(aSzIns);
   sqlite3Fts3SegmentsClose(p);
   return rc;
@@ -120317,12 +122864,10 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
   int rc;
   rc = sqlite3_exec(p->db, "SAVEPOINT fts3", 0, 0, 0);
   if( rc==SQLITE_OK ){
-    rc = fts3SegmentMerge(p, FTS3_SEGCURSOR_ALL);
-    if( rc==SQLITE_OK ){
-      rc = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0);
-      if( rc==SQLITE_OK ){
-        sqlite3Fts3PendingTermsClear(p);
-      }
+    rc = fts3DoOptimize(p, 1);
+    if( rc==SQLITE_OK || rc==SQLITE_DONE ){
+      int rc2 = sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0);
+      if( rc2!=SQLITE_OK ) rc = rc2;
     }else{
       sqlite3_exec(p->db, "ROLLBACK TO fts3", 0, 0, 0);
       sqlite3_exec(p->db, "RELEASE fts3", 0, 0, 0);
@@ -120511,51 +123056,6 @@ static int fts3ExprIterate(
   return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
 }
 
-/*
-** The argument to this function is always a phrase node. Its doclist 
-** (Fts3Expr.aDoclist[]) and the doclists associated with all phrase nodes
-** to the left of this one in the query tree have already been loaded.
-**
-** If this phrase node is part of a series of phrase nodes joined by 
-** NEAR operators (and is not the left-most of said series), then elements are
-** removed from the phrases doclist consistent with the NEAR restriction. If
-** required, elements may be removed from the doclists of phrases to the
-** left of this one that are part of the same series of NEAR operator 
-** connected phrases.
-**
-** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
-*/
-static int fts3ExprNearTrim(Fts3Expr *pExpr){
-  int rc = SQLITE_OK;
-  Fts3Expr *pParent = pExpr->pParent;
-
-  assert( pExpr->eType==FTSQUERY_PHRASE );
-  while( rc==SQLITE_OK
-   && pParent 
-   && pParent->eType==FTSQUERY_NEAR 
-   && pParent->pRight==pExpr 
-  ){
-    /* This expression (pExpr) is the right-hand-side of a NEAR operator. 
-    ** Find the expression to the left of the same operator.
-    */
-    int nNear = pParent->nNear;
-    Fts3Expr *pLeft = pParent->pLeft;
-
-    if( pLeft->eType!=FTSQUERY_PHRASE ){
-      assert( pLeft->eType==FTSQUERY_NEAR );
-      assert( pLeft->pRight->eType==FTSQUERY_PHRASE );
-      pLeft = pLeft->pRight;
-    }
-
-    rc = sqlite3Fts3ExprNearTrim(pLeft, pExpr, nNear);
-
-    pExpr = pLeft;
-    pParent = pExpr->pParent;
-  }
-
-  return rc;
-}
-
 /*
 ** This is an fts3ExprIterate() callback used while loading the doclists
 ** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
@@ -120563,20 +123063,13 @@ static int fts3ExprNearTrim(Fts3Expr *pExpr){
 */
 static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
   int rc = SQLITE_OK;
+  Fts3Phrase *pPhrase = pExpr->pPhrase;
   LoadDoclistCtx *p = (LoadDoclistCtx *)ctx;
 
   UNUSED_PARAMETER(iPhrase);
 
   p->nPhrase++;
-  p->nToken += pExpr->pPhrase->nToken;
-
-  if( pExpr->isLoaded==0 ){
-    rc = sqlite3Fts3ExprLoadDoclist(p->pCsr, pExpr);
-    pExpr->isLoaded = 1;
-    if( rc==SQLITE_OK ){
-      rc = fts3ExprNearTrim(pExpr);
-    }
-  }
+  p->nToken += pPhrase->nToken;
 
   return rc;
 }
@@ -120750,7 +123243,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
 
   pPhrase->nToken = pExpr->pPhrase->nToken;
 
-  pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol);
+  pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
   if( pCsr ){
     int iFirst = 0;
     pPhrase->pList = pCsr;
@@ -121107,26 +123600,6 @@ static int fts3ColumnlistCount(char **ppCollist){
   return nEntry;
 }
 
-static void fts3LoadColumnlistCounts(char **pp, u32 *aOut, int isGlobal){
-  char *pCsr = *pp;
-  while( *pCsr ){
-    int nHit;
-    sqlite3_int64 iCol = 0;
-    if( *pCsr==0x01 ){
-      pCsr++;
-      pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
-    }
-    nHit = fts3ColumnlistCount(&pCsr);
-    assert( nHit>0 );
-    if( isGlobal ){
-      aOut[iCol*3+1]++;
-    }
-    aOut[iCol*3] += nHit;
-  }
-  pCsr++;
-  *pp = pCsr;
-}
-
 /*
 ** fts3ExprIterate() callback used to collect the "global" matchinfo stats
 ** for a single query. 
@@ -121160,48 +123633,9 @@ static int fts3ExprGlobalHitsCb(
   void *pCtx                      /* Pointer to MatchInfo structure */
 ){
   MatchInfo *p = (MatchInfo *)pCtx;
-  Fts3Cursor *pCsr = p->pCursor;
-  char *pIter;
-  char *pEnd;
-  char *pFree = 0;
-  u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
-
-  assert( pExpr->isLoaded );
-  assert( pExpr->eType==FTSQUERY_PHRASE );
-
-  if( pCsr->pDeferred ){
-    Fts3Phrase *pPhrase = pExpr->pPhrase;
-    int ii;
-    for(ii=0; ii<pPhrase->nToken; ii++){
-      if( pPhrase->aToken[ii].bFulltext ) break;
-    }
-    if( ii<pPhrase->nToken ){
-      int nFree = 0;
-      int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
-      if( rc!=SQLITE_OK ) return rc;
-      pIter = pFree;
-      pEnd = &pFree[nFree];
-    }else{
-      int iCol;                   /* Column index */
-      for(iCol=0; iCol<p->nCol; iCol++){
-        aOut[iCol*3 + 1] = (u32)p->nDoc;
-        aOut[iCol*3 + 2] = (u32)p->nDoc;
-      }
-      return SQLITE_OK;
-    }
-  }else{
-    pIter = pExpr->aDoclist;
-    pEnd = &pExpr->aDoclist[pExpr->nDoclist];
-  }
-
-  /* Fill in the global hit count matrix row for this phrase. */
-  while( pIter<pEnd ){
-    while( *pIter++ & 0x80 );      /* Skip past docid. */
-    fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
-  }
-
-  sqlite3_free(pFree);
-  return SQLITE_OK;
+  return sqlite3Fts3EvalPhraseStats(
+      p->pCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol]
+  );
 }
 
 /*
@@ -121218,14 +123652,13 @@ static int fts3ExprLocalHitsCb(
   int iStart = iPhrase * p->nCol * 3;
   int i;
 
-  for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
-
-  if( pExpr->aDoclist ){
+  for(i=0; i<p->nCol; i++){
     char *pCsr;
-
-    pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
+    pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i);
     if( pCsr ){
-      fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
+      p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr);
+    }else{
+      p->aMatchinfo[iStart+i*3] = 0;
     }
   }
 
@@ -121295,7 +123728,7 @@ static int fts3MatchinfoSelectDoctotal(
 
   a = sqlite3_column_blob(pStmt, 0);
   a += sqlite3Fts3GetVarint(a, &nDoc);
-  if( nDoc==0 ) return SQLITE_CORRUPT;
+  if( nDoc==0 ) return SQLITE_CORRUPT_VTAB;
   *pnDoc = (u32)nDoc;
 
   if( paLen ) *paLen = a;
@@ -121311,9 +123744,8 @@ static int fts3MatchinfoSelectDoctotal(
 typedef struct LcsIterator LcsIterator;
 struct LcsIterator {
   Fts3Expr *pExpr;                /* Pointer to phrase expression */
-  char *pRead;                    /* Cursor used to iterate through aDoclist */
   int iPosOffset;                 /* Tokens count up to end of this phrase */
-  int iCol;                       /* Current column number */
+  char *pRead;                    /* Cursor used to iterate through aDoclist */
   int iPos;                       /* Current position */
 };
 
@@ -121344,17 +123776,10 @@ static int fts3LcsIteratorAdvance(LcsIterator *pIter){
   int rc = 0;
 
   pRead += sqlite3Fts3GetVarint(pRead, &iRead);
-  if( iRead==0 ){
-    pIter->iCol = LCS_ITERATOR_FINISHED;
+  if( iRead==0 || iRead==1 ){
+    pRead = 0;
     rc = 1;
   }else{
-    if( iRead==1 ){
-      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
-      pIter->iCol = (int)iRead;
-      pIter->iPos = pIter->iPosOffset;
-      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
-      rc = 1;
-    }
     pIter->iPos += (int)(iRead-2);
   }
 
@@ -121386,42 +123811,34 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
   if( !aIter ) return SQLITE_NOMEM;
   memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
   (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
+
   for(i=0; i<pInfo->nPhrase; i++){
     LcsIterator *pIter = &aIter[i];
     nToken -= pIter->pExpr->pPhrase->nToken;
     pIter->iPosOffset = nToken;
-    pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
-    if( pIter->pRead ){
-      pIter->iPos = pIter->iPosOffset;
-      fts3LcsIteratorAdvance(&aIter[i]);
-    }else{
-      pIter->iCol = LCS_ITERATOR_FINISHED;
-    }
   }
 
   for(iCol=0; iCol<pInfo->nCol; iCol++){
     int nLcs = 0;                 /* LCS value for this column */
     int nLive = 0;                /* Number of iterators in aIter not at EOF */
 
-    /* Loop through the iterators in aIter[]. Set nLive to the number of
-    ** iterators that point to a position-list corresponding to column iCol.
-    */
     for(i=0; i<pInfo->nPhrase; i++){
-      assert( aIter[i].iCol>=iCol );
-      if( aIter[i].iCol==iCol ) nLive++;
+      LcsIterator *pIt = &aIter[i];
+      pIt->pRead = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol);
+      if( pIt->pRead ){
+        pIt->iPos = pIt->iPosOffset;
+        fts3LcsIteratorAdvance(&aIter[i]);
+        nLive++;
+      }
     }
 
-    /* The following loop runs until all iterators in aIter[] have finished
-    ** iterating through positions in column iCol. Exactly one of the 
-    ** iterators is advanced each time the body of the loop is run.
-    */
     while( nLive>0 ){
       LcsIterator *pAdv = 0;      /* The iterator to advance by one position */
       int nThisLcs = 0;           /* LCS for the current iterator positions */
 
       for(i=0; i<pInfo->nPhrase; i++){
         LcsIterator *pIter = &aIter[i];
-        if( iCol!=pIter->iCol ){  
+        if( pIter->pRead==0 ){
           /* This iterator is already at EOF for this column. */
           nThisLcs = 0;
         }else{
@@ -121487,7 +123904,7 @@ static int fts3MatchinfoValues(
         
       case FTS3_MATCHINFO_NDOC:
         if( bGlobal ){
-          sqlite3_int64 nDoc;
+          sqlite3_int64 nDoc = 0;
           rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
           pInfo->aMatchinfo[0] = (u32)nDoc;
         }
@@ -121743,6 +124160,7 @@ struct TermOffset {
 };
 
 struct TermOffsetCtx {
+  Fts3Cursor *pCsr;
   int iCol;                       /* Column of table to populate aTerm for */
   int iTerm;
   sqlite3_int64 iDocid;
@@ -121760,7 +124178,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
   int iPos = 0;                   /* First position in position-list */
 
   UNUSED_PARAMETER(iPhrase);
-  pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol);
+  pList = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
   nTerm = pExpr->pPhrase->nToken;
   if( pList ){
     fts3GetDeltaPosition(&pList, &iPos);
@@ -121813,6 +124231,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
     goto offsets_out;
   }
   sCtx.iDocid = pCsr->iPrevId;
+  sCtx.pCsr = pCsr;
 
   /* Loop through the table columns, appending offset information to 
   ** string-buffer res for each column.
@@ -121888,7 +124307,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
           );
           rc = fts3StringAppend(&res, aBuffer, -1);
         }else if( rc==SQLITE_DONE ){
-          rc = SQLITE_CORRUPT;
+          rc = SQLITE_CORRUPT_VTAB;
         }
       }
     }
@@ -122476,17 +124895,17 @@ nodeAcquire(
   if( pNode && iNode==1 ){
     pRtree->iDepth = readInt16(pNode->zData);
     if( pRtree->iDepth>RTREE_MAX_DEPTH ){
-      rc = SQLITE_CORRUPT;
+      rc = SQLITE_CORRUPT_VTAB;
     }
   }
 
   /* If no error has occurred so far, check if the "number of entries"
   ** field on the node is too large. If so, set the return code to 
-  ** SQLITE_CORRUPT.
+  ** SQLITE_CORRUPT_VTAB.
   */
   if( pNode && rc==SQLITE_OK ){
     if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){
-      rc = SQLITE_CORRUPT;
+      rc = SQLITE_CORRUPT_VTAB;
     }
   }
 
@@ -122494,7 +124913,7 @@ nodeAcquire(
     if( pNode!=0 ){
       nodeHashInsert(pRtree, pNode);
     }else{
-      rc = SQLITE_CORRUPT;
+      rc = SQLITE_CORRUPT_VTAB;
     }
     *ppNode = pNode;
   }else{
@@ -123021,7 +125440,7 @@ static int nodeRowidIndex(
       return SQLITE_OK;
     }
   }
-  return SQLITE_CORRUPT;
+  return SQLITE_CORRUPT_VTAB;
 }
 
 /*
@@ -123380,7 +125799,7 @@ static float cellArea(Rtree *pRtree, RtreeCell *p){
   float area = 1.0;
   int ii;
   for(ii=0; ii<(pRtree->nDim*2); ii+=2){
-    area = area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
+    area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
   }
   return area;
 }
@@ -123393,7 +125812,7 @@ static float cellMargin(Rtree *pRtree, RtreeCell *p){
   float margin = 0.0;
   int ii;
   for(ii=0; ii<(pRtree->nDim*2); ii+=2){
-    margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
+    margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
   }
   return margin;
 }
@@ -123478,7 +125897,7 @@ static float cellOverlap(
           o = 0.0;
           break;
         }else{
-          o = o * (x2-x1);
+          o = o * (float)(x2-x1);
         }
       }
       overlap += o;
@@ -123497,12 +125916,12 @@ static float cellOverlapEnlargement(
   int nCell, 
   int iExclude
 ){
-  float before;
-  float after;
+  double before;
+  double after;
   before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
   cellUnion(pRtree, p, pInsert);
   after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
-  return after-before;
+  return (float)(after-before);
 }
 #endif
 
@@ -123524,11 +125943,11 @@ static int ChooseLeaf(
 
   for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
     int iCell;
-    sqlite3_int64 iBest;
+    sqlite3_int64 iBest = 0;
 
-    float fMinGrowth;
-    float fMinArea;
-    float fMinOverlap;
+    float fMinGrowth = 0.0;
+    float fMinArea = 0.0;
+    float fMinOverlap = 0.0;
 
     int nCell = NCELL(pNode);
     RtreeCell cell;
@@ -123616,7 +126035,7 @@ static int AdjustTree(
     int iCell;
 
     if( nodeParentIndex(pRtree, p, &iCell) ){
-      return SQLITE_CORRUPT;
+      return SQLITE_CORRUPT_VTAB;
     }
 
     nodeGetCell(pRtree, pParent, iCell, &cell);
@@ -123958,9 +126377,9 @@ static int splitNodeStartree(
   int *aSpare;
   int ii;
 
-  int iBestDim;
-  int iBestSplit;
-  float fBestMargin;
+  int iBestDim = 0;
+  int iBestSplit = 0;
+  float fBestMargin = 0.0;
 
   int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
 
@@ -123982,9 +126401,9 @@ static int splitNodeStartree(
 
   for(ii=0; ii<pRtree->nDim; ii++){
     float margin = 0.0;
-    float fBestOverlap;
-    float fBestArea;
-    int iBestLeft;
+    float fBestOverlap = 0.0;
+    float fBestArea = 0.0;
+    int iBestLeft = 0;
     int nLeft;
 
     for(
@@ -124288,7 +126707,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
     }
     rc = sqlite3_reset(pRtree->pReadParent);
     if( rc==SQLITE_OK ) rc = rc2;
-    if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT;
+    if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB;
     pChild = pChild->pParent;
   }
   return rc;
@@ -124299,7 +126718,7 @@ static int deleteCell(Rtree *, RtreeNode *, int, int);
 static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
   int rc;
   int rc2;
-  RtreeNode *pParent;
+  RtreeNode *pParent = 0;
   int iCell;
 
   assert( pNode->nRef==1 );
@@ -124447,19 +126866,19 @@ static int Reinsert(
     }
     aOrder[ii] = ii;
     for(iDim=0; iDim<pRtree->nDim; iDim++){
-      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
-      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
+      aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]);
+      aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]);
     }
   }
   for(iDim=0; iDim<pRtree->nDim; iDim++){
-    aCenterCoord[iDim] = aCenterCoord[iDim]/((float)nCell*2.0);
+    aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0));
   }
 
   for(ii=0; ii<nCell; ii++){
     aDistance[ii] = 0.0;
     for(iDim=0; iDim<pRtree->nDim; iDim++){
-      float coord = DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
-          DCOORD(aCell[ii].aCoord[iDim*2]);
+      float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
+          DCOORD(aCell[ii].aCoord[iDim*2]));
       aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
     }
   }
@@ -124558,10 +126977,10 @@ static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){
     /* Find a node to store this cell in. pNode->iNode currently contains
     ** the height of the sub-tree headed by the cell.
     */
-    rc = ChooseLeaf(pRtree, &cell, pNode->iNode, &pInsert);
+    rc = ChooseLeaf(pRtree, &cell, (int)pNode->iNode, &pInsert);
     if( rc==SQLITE_OK ){
       int rc2;
-      rc = rtreeInsertCell(pRtree, pInsert, &cell, pNode->iNode);
+      rc = rtreeInsertCell(pRtree, pInsert, &cell, (int)pNode->iNode);
       rc2 = nodeRelease(pRtree, pInsert);
       if( rc==SQLITE_OK ){
         rc = rc2;
@@ -124585,113 +127004,119 @@ static int newRowid(Rtree *pRtree, i64 *piRowid){
 }
 
 /*
-** The xUpdate method for rtree module virtual tables.
+** Remove the entry with rowid=iDelete from the r-tree structure.
 */
-static int rtreeUpdate(
-  sqlite3_vtab *pVtab, 
-  int nData, 
-  sqlite3_value **azData, 
-  sqlite_int64 *pRowid
-){
-  Rtree *pRtree = (Rtree *)pVtab;
-  int rc = SQLITE_OK;
+static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
+  int rc;                         /* Return code */
+  RtreeNode *pLeaf;               /* Leaf node containing record iDelete */
+  int iCell;                      /* Index of iDelete cell in pLeaf */
+  RtreeNode *pRoot;               /* Root node of rtree structure */
 
-  rtreeReference(pRtree);
 
-  assert(nData>=1);
+  /* Obtain a reference to the root node to initialise Rtree.iDepth */
+  rc = nodeAcquire(pRtree, 1, 0, &pRoot);
 
-  /* If azData[0] is not an SQL NULL value, it is the rowid of a
-  ** record to delete from the r-tree table. The following block does
-  ** just that.
+  /* Obtain a reference to the leaf node that contains the entry 
+  ** about to be deleted. 
   */
-  if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){
-    i64 iDelete;                /* The rowid to delete */
-    RtreeNode *pLeaf;           /* Leaf node containing record iDelete */
-    int iCell;                  /* Index of iDelete cell in pLeaf */
-    RtreeNode *pRoot;
-
-    /* Obtain a reference to the root node to initialise Rtree.iDepth */
-    rc = nodeAcquire(pRtree, 1, 0, &pRoot);
+  if( rc==SQLITE_OK ){
+    rc = findLeafNode(pRtree, iDelete, &pLeaf);
+  }
 
-    /* Obtain a reference to the leaf node that contains the entry 
-    ** about to be deleted. 
-    */
+  /* Delete the cell in question from the leaf node. */
+  if( rc==SQLITE_OK ){
+    int rc2;
+    rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
     if( rc==SQLITE_OK ){
-      iDelete = sqlite3_value_int64(azData[0]);
-      rc = findLeafNode(pRtree, iDelete, &pLeaf);
+      rc = deleteCell(pRtree, pLeaf, iCell, 0);
     }
-
-    /* Delete the cell in question from the leaf node. */
+    rc2 = nodeRelease(pRtree, pLeaf);
     if( rc==SQLITE_OK ){
-      int rc2;
-      rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
-      if( rc==SQLITE_OK ){
-        rc = deleteCell(pRtree, pLeaf, iCell, 0);
-      }
-      rc2 = nodeRelease(pRtree, pLeaf);
-      if( rc==SQLITE_OK ){
-        rc = rc2;
-      }
+      rc = rc2;
     }
+  }
 
-    /* Delete the corresponding entry in the <rtree>_rowid table. */
-    if( rc==SQLITE_OK ){
-      sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete);
-      sqlite3_step(pRtree->pDeleteRowid);
-      rc = sqlite3_reset(pRtree->pDeleteRowid);
-    }
+  /* Delete the corresponding entry in the <rtree>_rowid table. */
+  if( rc==SQLITE_OK ){
+    sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete);
+    sqlite3_step(pRtree->pDeleteRowid);
+    rc = sqlite3_reset(pRtree->pDeleteRowid);
+  }
 
-    /* Check if the root node now has exactly one child. If so, remove
-    ** it, schedule the contents of the child for reinsertion and 
-    ** reduce the tree height by one.
-    **
-    ** This is equivalent to copying the contents of the child into
-    ** the root node (the operation that Gutman's paper says to perform 
-    ** in this scenario).
-    */
-    if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
-      int rc2;
-      RtreeNode *pChild;
-      i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
-      rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
-      if( rc==SQLITE_OK ){
-        rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
-      }
-      rc2 = nodeRelease(pRtree, pChild);
-      if( rc==SQLITE_OK ) rc = rc2;
-      if( rc==SQLITE_OK ){
-        pRtree->iDepth--;
-        writeInt16(pRoot->zData, pRtree->iDepth);
-        pRoot->isDirty = 1;
-      }
+  /* Check if the root node now has exactly one child. If so, remove
+  ** it, schedule the contents of the child for reinsertion and 
+  ** reduce the tree height by one.
+  **
+  ** This is equivalent to copying the contents of the child into
+  ** the root node (the operation that Gutman's paper says to perform 
+  ** in this scenario).
+  */
+  if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
+    int rc2;
+    RtreeNode *pChild;
+    i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
+    rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
+    if( rc==SQLITE_OK ){
+      rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
     }
-
-    /* Re-insert the contents of any underfull nodes removed from the tree. */
-    for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){
-      if( rc==SQLITE_OK ){
-        rc = reinsertNodeContent(pRtree, pLeaf);
-      }
-      pRtree->pDeleted = pLeaf->pNext;
-      sqlite3_free(pLeaf);
+    rc2 = nodeRelease(pRtree, pChild);
+    if( rc==SQLITE_OK ) rc = rc2;
+    if( rc==SQLITE_OK ){
+      pRtree->iDepth--;
+      writeInt16(pRoot->zData, pRtree->iDepth);
+      pRoot->isDirty = 1;
     }
+  }
 
-    /* Release the reference to the root node. */
+  /* Re-insert the contents of any underfull nodes removed from the tree. */
+  for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){
     if( rc==SQLITE_OK ){
-      rc = nodeRelease(pRtree, pRoot);
-    }else{
-      nodeRelease(pRtree, pRoot);
+      rc = reinsertNodeContent(pRtree, pLeaf);
     }
+    pRtree->pDeleted = pLeaf->pNext;
+    sqlite3_free(pLeaf);
   }
 
-  /* If the azData[] array contains more than one element, elements
-  ** (azData[2]..azData[argc-1]) contain a new record to insert into
-  ** the r-tree structure.
+  /* Release the reference to the root node. */
+  if( rc==SQLITE_OK ){
+    rc = nodeRelease(pRtree, pRoot);
+  }else{
+    nodeRelease(pRtree, pRoot);
+  }
+
+  return rc;
+}
+
+/*
+** The xUpdate method for rtree module virtual tables.
+*/
+static int rtreeUpdate(
+  sqlite3_vtab *pVtab, 
+  int nData, 
+  sqlite3_value **azData, 
+  sqlite_int64 *pRowid
+){
+  Rtree *pRtree = (Rtree *)pVtab;
+  int rc = SQLITE_OK;
+  RtreeCell cell;                 /* New cell to insert if nData>1 */
+  int bHaveRowid = 0;             /* Set to 1 after new rowid is determined */
+
+  rtreeReference(pRtree);
+  assert(nData>=1);
+
+  /* Constraint handling. A write operation on an r-tree table may return
+  ** SQLITE_CONSTRAINT for two reasons:
+  **
+  **   1. A duplicate rowid value, or
+  **   2. The supplied data violates the "x2>=x1" constraint.
+  **
+  ** In the first case, if the conflict-handling mode is REPLACE, then
+  ** the conflicting row can be removed before proceeding. In the second
+  ** case, SQLITE_CONSTRAINT must be returned regardless of the
+  ** conflict-handling mode specified by the user.
   */
-  if( rc==SQLITE_OK && nData>1 ){
-    /* Insert a new record into the r-tree */
-    RtreeCell cell;
+  if( nData>1 ){
     int ii;
-    RtreeNode *pLeaf;
 
     /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
     assert( nData==(pRtree->nDim*2 + 3) );
@@ -124715,18 +127140,49 @@ static int rtreeUpdate(
       }
     }
 
-    /* Figure out the rowid of the new row. */
-    if( sqlite3_value_type(azData[2])==SQLITE_NULL ){
-      rc = newRowid(pRtree, &cell.iRowid);
-    }else{
+    /* If a rowid value was supplied, check if it is already present in 
+    ** the table. If so, the constraint has failed. */
+    if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){
       cell.iRowid = sqlite3_value_int64(azData[2]);
-      sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
-      if( SQLITE_ROW==sqlite3_step(pRtree->pReadRowid) ){
-        sqlite3_reset(pRtree->pReadRowid);
-        rc = SQLITE_CONSTRAINT;
-        goto constraint;
+      if( sqlite3_value_type(azData[0])==SQLITE_NULL
+       || sqlite3_value_int64(azData[0])!=cell.iRowid
+      ){
+        int steprc;
+        sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
+        steprc = sqlite3_step(pRtree->pReadRowid);
+        rc = sqlite3_reset(pRtree->pReadRowid);
+        if( SQLITE_ROW==steprc ){
+          if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
+            rc = rtreeDeleteRowid(pRtree, cell.iRowid);
+          }else{
+            rc = SQLITE_CONSTRAINT;
+            goto constraint;
+          }
+        }
       }
-      rc = sqlite3_reset(pRtree->pReadRowid);
+      bHaveRowid = 1;
+    }
+  }
+
+  /* If azData[0] is not an SQL NULL value, it is the rowid of a
+  ** record to delete from the r-tree table. The following block does
+  ** just that.
+  */
+  if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){
+    rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0]));
+  }
+
+  /* If the azData[] array contains more than one element, elements
+  ** (azData[2]..azData[argc-1]) contain a new record to insert into
+  ** the r-tree structure.
+  */
+  if( rc==SQLITE_OK && nData>1 ){
+    /* Insert the new record into the r-tree */
+    RtreeNode *pLeaf;
+
+    /* Figure out the rowid of the new row. */
+    if( bHaveRowid==0 ){
+      rc = newRowid(pRtree, &cell.iRowid);
     }
     *pRowid = cell.iRowid;
 
@@ -124771,7 +127227,7 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
 }
 
 static sqlite3_module rtreeModule = {
-  0,                         /* iVersion */
+  0,                          /* iVersion */
   rtreeCreate,                /* xCreate - create a table */
   rtreeConnect,               /* xConnect - connect to an existing table */
   rtreeBestIndex,             /* xBestIndex - Determine search strategy */
@@ -124790,7 +127246,10 @@ static sqlite3_module rtreeModule = {
   0,                          /* xCommit - commit transaction */
   0,                          /* xRollback - rollback transaction */
   0,                          /* xFindFunction - function overloading */
-  rtreeRename                 /* xRename - rename the table */
+  rtreeRename,                /* xRename - rename the table */
+  0,                          /* xSavepoint */
+  0,                          /* xRelease */
+  0                           /* xRollbackTo */
 };
 
 static int rtreeSqlInit(
@@ -124910,7 +127369,7 @@ static int getNodeSize(
   int rc;
   char *zSql;
   if( isCreate ){
-    int iPageSize;
+    int iPageSize = 0;
     zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
     rc = getIntFromStmt(db, zSql, &iPageSize);
     if( rc==SQLITE_OK ){
@@ -124967,6 +127426,8 @@ static int rtreeInit(
     return SQLITE_ERROR;
   }
 
+  sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+
   /* Allocate the sqlite3_vtab structure */
   nDb = strlen(argv[1]);
   nName = strlen(argv[2]);
@@ -125711,10 +128172,7 @@ SQLITE_API int sqlite3_extension_init(
 **
 *************************************************************************
 ** This file implements a tokenizer for fts3 based on the ICU library.
-** 
-** $Id: fts3_icu.c,v 1.3 2008/09/01 18:34:20 danielk1977 Exp $
 */
-
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
 #ifdef SQLITE_ENABLE_ICU
 
index 3b7eb94dda8a9535f16a59cf15ecd936c2904b92..ed9edbd20297e1a255a771eced97433d6ad8a74b 100644 (file)
@@ -107,9 +107,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.6.2"
-#define SQLITE_VERSION_NUMBER 3007006
-#define SQLITE_SOURCE_ID      "2011-04-17 17:25:17 154ddbc17120be2915eb03edc52af1225eb7cb5e"
+#define SQLITE_VERSION        "3.7.7.1"
+#define SQLITE_VERSION_NUMBER 3007007
+#define SQLITE_SOURCE_ID      "2011-06-28 17:39:05 af0d91adf497f5f36ec3813f04235a6e195a605f"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -310,7 +310,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
 ** argument.  ^If the callback function of the 3rd argument to
 ** sqlite3_exec() is not NULL, then it is invoked for each result row
 ** coming out of the evaluated SQL statements.  ^The 4th argument to
-** to sqlite3_exec() is relayed through to the 1st argument of each
+** sqlite3_exec() is relayed through to the 1st argument of each
 ** callback invocation.  ^If the callback pointer to sqlite3_exec()
 ** is NULL, then no callback is ever invoked and result rows are
 ** ignored.
@@ -375,7 +375,8 @@ SQLITE_API int sqlite3_exec(
 **
 ** New error codes may be added in future versions of SQLite.
 **
-** See also: [SQLITE_IOERR_READ | extended result codes]
+** See also: [SQLITE_IOERR_READ | extended result codes],
+** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes].
 */
 #define SQLITE_OK           0   /* Successful result */
 /* beginning-of-error-codes */
@@ -452,17 +453,21 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_IOERR_SHMOPEN           (SQLITE_IOERR | (18<<8))
 #define SQLITE_IOERR_SHMSIZE           (SQLITE_IOERR | (19<<8))
 #define SQLITE_IOERR_SHMLOCK           (SQLITE_IOERR | (20<<8))
+#define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
+#define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
+#define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
+#define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
+#define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
 
 /*
 ** CAPI3REF: Flags For File Open Operations
 **
 ** These bit values are intended for use in the
 ** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
+** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
 */
 #define SQLITE_OPEN_READONLY         0x00000001  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_READWRITE        0x00000002  /* Ok for sqlite3_open_v2() */
@@ -470,6 +475,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_OPEN_DELETEONCLOSE    0x00000008  /* VFS only */
 #define SQLITE_OPEN_EXCLUSIVE        0x00000010  /* VFS only */
 #define SQLITE_OPEN_AUTOPROXY        0x00000020  /* VFS only */
+#define SQLITE_OPEN_URI              0x00000040  /* Ok for sqlite3_open_v2() */
 #define SQLITE_OPEN_MAIN_DB          0x00000100  /* VFS only */
 #define SQLITE_OPEN_TEMP_DB          0x00000200  /* VFS only */
 #define SQLITE_OPEN_TRANSIENT_DB     0x00000400  /* VFS only */
@@ -580,17 +586,18 @@ struct sqlite3_file {
 /*
 ** CAPI3REF: OS Interface File Virtual Methods Object
 **
-** Every file opened by the [sqlite3_vfs] xOpen method populates an
+** Every file opened by the [sqlite3_vfs.xOpen] method populates an
 ** [sqlite3_file] object (or, more commonly, a subclass of the
 ** [sqlite3_file] object) with a pointer to an instance of this object.
 ** This object defines the methods used to perform various operations
 ** against the open file represented by the [sqlite3_file] object.
 **
-** If the xOpen method sets the sqlite3_file.pMethods element 
+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element 
 ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
-** may be invoked even if the xOpen reported that it failed.  The
-** only way to prevent a call to xClose following a failed xOpen
-** is for the xOpen to set the sqlite3_file.pMethods element to NULL.
+** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed.  The
+** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
+** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element
+** to NULL.
 **
 ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
 ** [SQLITE_SYNC_FULL].  The first choice is the normal fsync().
@@ -762,7 +769,8 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 **
 ** An instance of the sqlite3_vfs object defines the interface between
 ** the SQLite core and the underlying operating system.  The "vfs"
-** in the name of the object stands for "virtual file system".
+** in the name of the object stands for "virtual file system".  See
+** the [VFS | VFS documentation] for further information.
 **
 ** The value of the iVersion field is initially 1 but may be larger in
 ** future versions of SQLite.  Additional fields may be appended to this
@@ -791,6 +799,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** The zName field holds the name of the VFS module.  The name must
 ** be unique across all VFS modules.
 **
+** [[sqlite3_vfs.xOpen]]
 ** ^SQLite guarantees that the zFilename parameter to xOpen
 ** is either a NULL pointer or string obtained
 ** from xFullPathname() with an optional suffix added.
@@ -868,6 +877,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** element will be valid after xOpen returns regardless of the success
 ** or failure of the xOpen call.
 **
+** [[sqlite3_vfs.xAccess]]
 ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
 ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to
 ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ]
@@ -892,7 +902,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
 ** method returns a Julian Day Number for the current date and time as
 ** a floating point value.
 ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
-** Day Number multipled by 86400000 (the number of milliseconds in 
+** Day Number multiplied by 86400000 (the number of milliseconds in 
 ** a 24-hour day).  
 ** ^SQLite will use the xCurrentTimeInt64() method to get the current
 ** date and time if that method is available (if iVersion is 2 or 
@@ -1114,9 +1124,9 @@ SQLITE_API int sqlite3_os_end(void);
 ** implementation of an application-defined [sqlite3_os_init()].
 **
 ** The first argument to sqlite3_config() is an integer
-** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines
+** [configuration option] that determines
 ** what property of SQLite is to be configured.  Subsequent arguments
-** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option]
+** vary depending on the [configuration option]
 ** in the first argument.
 **
 ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
@@ -1226,6 +1236,7 @@ struct sqlite3_mem_methods {
 
 /*
 ** CAPI3REF: Configuration Options
+** KEYWORDS: {configuration option}
 **
 ** These constants are the available integer configuration options that
 ** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1238,7 +1249,7 @@ struct sqlite3_mem_methods {
 ** is invoked.
 **
 ** <dl>
-** <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
+** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Single-thread.  In other words, it disables
 ** all mutexing and puts SQLite into a mode where it can only be used
@@ -1249,7 +1260,7 @@ struct sqlite3_mem_methods {
 ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
 ** configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_MULTITHREAD</dt>
+** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Multi-thread.  In other words, it disables
 ** mutexing on [database connection] and [prepared statement] objects.
@@ -1263,7 +1274,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
 ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_SERIALIZED</dt>
+** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt>
 ** <dd>There are no arguments to this option.  ^This option sets the
 ** [threading mode] to Serialized. In other words, this option enables
 ** all mutexes including the recursive
@@ -1279,7 +1290,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the
 ** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
 **
-** <dt>SQLITE_CONFIG_MALLOC</dt>
+** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mem_methods] structure.  The argument specifies
 ** alternative low-level memory allocation routines to be used in place of
@@ -1287,7 +1298,7 @@ struct sqlite3_mem_methods {
 ** its own private copy of the content of the [sqlite3_mem_methods] structure
 ** before the [sqlite3_config()] call returns.</dd>
 **
-** <dt>SQLITE_CONFIG_GETMALLOC</dt>
+** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mem_methods] structure.  The [sqlite3_mem_methods]
 ** structure is filled with the currently defined memory allocation routines.)^
@@ -1295,7 +1306,7 @@ struct sqlite3_mem_methods {
 ** routines with a wrapper that simulations memory allocation failure or
 ** tracks memory usage, for example. </dd>
 **
-** <dt>SQLITE_CONFIG_MEMSTATUS</dt>
+** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
 ** <dd> ^This option takes single argument of type int, interpreted as a 
 ** boolean, which enables or disables the collection of memory allocation 
 ** statistics. ^(When memory allocation statistics are disabled, the 
@@ -1311,7 +1322,7 @@ struct sqlite3_mem_methods {
 ** allocation statistics are disabled by default.
 ** </dd>
 **
-** <dt>SQLITE_CONFIG_SCRATCH</dt>
+** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite can use for
 ** scratch memory.  There are three arguments:  A pointer an 8-byte
 ** aligned memory buffer from which the scratch allocations will be
@@ -1327,9 +1338,9 @@ struct sqlite3_mem_methods {
 ** scratch memory beyond what is provided by this configuration option, then 
 ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd>
 **
-** <dt>SQLITE_CONFIG_PAGECACHE</dt>
+** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite can use for
-** the database page cache with the default page cache implemenation.  
+** the database page cache with the default page cache implementation.  
 ** This configuration should not be used if an application-define page
 ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option.
 ** There are three arguments to this option: A pointer to 8-byte aligned
@@ -1348,7 +1359,7 @@ struct sqlite3_mem_methods {
 ** be aligned to an 8-byte boundary or subsequent behavior of SQLite
 ** will be undefined.</dd>
 **
-** <dt>SQLITE_CONFIG_HEAP</dt>
+** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
 ** <dd> ^This option specifies a static memory buffer that SQLite will use
 ** for all of its dynamic memory allocation needs beyond those provided
 ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
@@ -1365,7 +1376,7 @@ struct sqlite3_mem_methods {
 ** The minimum allocation size is capped at 2^12. Reasonable values
 ** for the minimum allocation size are 2^5 through 2^8.</dd>
 **
-** <dt>SQLITE_CONFIG_MUTEX</dt>
+** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mutex_methods] structure.  The argument specifies
 ** alternative low-level mutex routines to be used in place
@@ -1377,7 +1388,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will
 ** return [SQLITE_ERROR].</dd>
 **
-** <dt>SQLITE_CONFIG_GETMUTEX</dt>
+** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** instance of the [sqlite3_mutex_methods] structure.  The
 ** [sqlite3_mutex_methods]
@@ -1390,7 +1401,7 @@ struct sqlite3_mem_methods {
 ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
 ** return [SQLITE_ERROR].</dd>
 **
-** <dt>SQLITE_CONFIG_LOOKASIDE</dt>
+** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
 ** <dd> ^(This option takes two arguments that determine the default
 ** memory allocation for the lookaside memory allocator on each
 ** [database connection].  The first argument is the
@@ -1400,18 +1411,18 @@ struct sqlite3_mem_methods {
 ** verb to [sqlite3_db_config()] can be used to change the lookaside
 ** configuration on individual connections.)^ </dd>
 **
-** <dt>SQLITE_CONFIG_PCACHE</dt>
+** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to
 ** an [sqlite3_pcache_methods] object.  This object specifies the interface
 ** to a custom page cache implementation.)^  ^SQLite makes a copy of the
 ** object and uses it for page cache memory allocations.</dd>
 **
-** <dt>SQLITE_CONFIG_GETPCACHE</dt>
+** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt>
 ** <dd> ^(This option takes a single argument which is a pointer to an
 ** [sqlite3_pcache_methods] object.  SQLite copies of the current
 ** page cache implementation into that object.)^ </dd>
 **
-** <dt>SQLITE_CONFIG_LOG</dt>
+** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
 ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
 ** function with a call signature of void(*)(void*,int,const char*), 
 ** and a pointer to void. ^If the function pointer is not NULL, it is
@@ -1429,6 +1440,18 @@ struct sqlite3_mem_methods {
 ** In a multi-threaded application, the application-defined logger
 ** function must be threadsafe. </dd>
 **
+** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
+** <dd> This option takes a single argument of type int. If non-zero, then
+** URI handling is globally enabled. If the parameter is zero, then URI handling
+** is globally disabled. If URI handling is globally enabled, all filenames
+** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
+** specified as part of [ATTACH] commands are interpreted as URIs, regardless
+** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
+** connection is opened. If it is globally disabled, filenames are
+** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the
+** database connection is opened. By default, URI handling is globally
+** disabled. The default value may be changed by compiling with the
+** [SQLITE_USE_URI] symbol defined.
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1447,6 +1470,7 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_PCACHE       14  /* sqlite3_pcache_methods* */
 #define SQLITE_CONFIG_GETPCACHE    15  /* sqlite3_pcache_methods* */
 #define SQLITE_CONFIG_LOG          16  /* xFunc, void* */
+#define SQLITE_CONFIG_URI          17  /* int */
 
 /*
 ** CAPI3REF: Database Connection Configuration Options
@@ -1532,13 +1556,17 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
 **
 ** ^This routine returns the [rowid] of the most recent
 ** successful [INSERT] into the database from the [database connection]
-** in the first argument.  ^If no successful [INSERT]s
+** in the first argument.  ^As of SQLite version 3.7.7, this routines
+** records the last insert rowid of both ordinary tables and [virtual tables].
+** ^If no successful [INSERT]s
 ** have ever occurred on that database connection, zero is returned.
 **
-** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted
-** row is returned by this routine as long as the trigger is running.
-** But once the trigger terminates, the value returned by this routine
-** reverts to the last value inserted before the trigger fired.)^
+** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
+** method, then this routine will return the [rowid] of the inserted
+** row as long as the trigger or virtual table method is running.
+** But once the trigger or virtual table method ends, the value returned 
+** by this routine reverts to what it was before the trigger or virtual
+** table method began.)^
 **
 ** ^An [INSERT] that fails due to a constraint violation is not a
 ** successful [INSERT] and does not change the value returned by this
@@ -2201,6 +2229,9 @@ SQLITE_API int sqlite3_set_authorizer(
 ** to signal SQLite whether or not the action is permitted.  See the
 ** [sqlite3_set_authorizer | authorizer documentation] for additional
 ** information.
+**
+** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code]
+** from the [sqlite3_vtab_on_conflict()] interface.
 */
 #define SQLITE_DENY   1   /* Abort the SQL statement with an error */
 #define SQLITE_IGNORE 2   /* Don't allow access, but don't generate an error */
@@ -2323,7 +2354,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 /*
 ** CAPI3REF: Opening A New Database Connection
 **
-** ^These routines open an SQLite database file whose name is given by the
+** ^These routines open an SQLite database file as specified by the 
 ** filename argument. ^The filename argument is interpreted as UTF-8 for
 ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
 ** order for sqlite3_open16(). ^(A [database connection] handle is usually
@@ -2350,7 +2381,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** sqlite3_open_v2() can take one of
 ** the following three values, optionally combined with the 
 ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^
+** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
 **
 ** <dl>
 ** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
@@ -2369,9 +2400,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** </dl>
 **
 ** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above or one of the combinations shown above combined
-** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX],
-** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags,
+** combinations shown above optionally combined with other
+** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
 ** then the behavior is undefined.
 **
 ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection
@@ -2386,6 +2416,11 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not
 ** participate in [shared cache mode] even if it is enabled.
 **
+** ^The fourth parameter to sqlite3_open_v2() is the name of the
+** [sqlite3_vfs] object that defines the operating system interface that
+** the new database connection should use.  ^If the fourth parameter is
+** a NULL pointer then the default [sqlite3_vfs] object is used.
+**
 ** ^If the filename is ":memory:", then a private, temporary in-memory database
 ** is created for the connection.  ^This in-memory database will vanish when
 ** the database connection is closed.  Future versions of SQLite might
@@ -2398,10 +2433,111 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
 ** on-disk database will be created.  ^This private database will be
 ** automatically deleted as soon as the database connection is closed.
 **
-** ^The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system interface that
-** the new database connection should use.  ^If the fourth parameter is
-** a NULL pointer then the default [sqlite3_vfs] object is used.
+** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3>
+**
+** ^If [URI filename] interpretation is enabled, and the filename argument
+** begins with "file:", then the filename is interpreted as a URI. ^URI
+** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is
+** set in the fourth argument to sqlite3_open_v2(), or if it has
+** been enabled globally using the [SQLITE_CONFIG_URI] option with the
+** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option.
+** As of SQLite version 3.7.7, URI filename interpretation is turned off
+** by default, but future releases of SQLite might enable URI filename
+** interpretation by default.  See "[URI filenames]" for additional
+** information.
+**
+** URI filenames are parsed according to RFC 3986. ^If the URI contains an
+** authority, then it must be either an empty string or the string 
+** "localhost". ^If the authority is not an empty string or "localhost", an 
+** error is returned to the caller. ^The fragment component of a URI, if 
+** present, is ignored.
+**
+** ^SQLite uses the path component of the URI as the name of the disk file
+** which contains the database. ^If the path begins with a '/' character, 
+** then it is interpreted as an absolute path. ^If the path does not begin 
+** with a '/' (meaning that the authority section is omitted from the URI)
+** then the path is interpreted as a relative path. 
+** ^On windows, the first component of an absolute path 
+** is a drive specification (e.g. "C:").
+**
+** [[core URI query parameters]]
+** The query component of a URI may contain parameters that are interpreted
+** either by SQLite itself, or by a [VFS | custom VFS implementation].
+** SQLite interprets the following three query parameters:
+**
+** <ul>
+**   <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
+**     a VFS object that provides the operating system interface that should
+**     be used to access the database file on disk. ^If this option is set to
+**     an empty string the default VFS object is used. ^Specifying an unknown
+**     VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is
+**     present, then the VFS specified by the option takes precedence over
+**     the value passed as the fourth parameter to sqlite3_open_v2().
+**
+**   <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or
+**     "rwc". Attempting to set it to any other value is an error)^. 
+**     ^If "ro" is specified, then the database is opened for read-only 
+**     access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the 
+**     third argument to sqlite3_prepare_v2(). ^If the mode option is set to 
+**     "rw", then the database is opened for read-write (but not create) 
+**     access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had 
+**     been set. ^Value "rwc" is equivalent to setting both 
+**     SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is 
+**     used, it is an error to specify a value for the mode parameter that is 
+**     less restrictive than that specified by the flags passed as the third 
+**     parameter.
+**
+**   <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
+**     "private". ^Setting it to "shared" is equivalent to setting the
+**     SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
+**     sqlite3_open_v2(). ^Setting the cache parameter to "private" is 
+**     equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
+**     ^If sqlite3_open_v2() is used and the "cache" parameter is present in
+**     a URI filename, its value overrides any behaviour requested by setting
+**     SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
+** </ul>
+**
+** ^Specifying an unknown parameter in the query component of a URI is not an
+** error.  Future versions of SQLite might understand additional query
+** parameters.  See "[query parameters with special meaning to SQLite]" for
+** additional information.
+**
+** [[URI filename examples]] <h3>URI filename examples</h3>
+**
+** <table border="1" align=center cellpadding=5>
+** <tr><th> URI filenames <th> Results
+** <tr><td> file:data.db <td> 
+**          Open the file "data.db" in the current directory.
+** <tr><td> file:/home/fred/data.db<br>
+**          file:///home/fred/data.db <br> 
+**          file://localhost/home/fred/data.db <br> <td> 
+**          Open the database file "/home/fred/data.db".
+** <tr><td> file://darkstar/home/fred/data.db <td> 
+**          An error. "darkstar" is not a recognized authority.
+** <tr><td style="white-space:nowrap"> 
+**          file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
+**     <td> Windows only: Open the file "data.db" on fred's desktop on drive
+**          C:. Note that the %20 escaping in this example is not strictly 
+**          necessary - space characters can be used literally
+**          in URI filenames.
+** <tr><td> file:data.db?mode=ro&cache=private <td> 
+**          Open file "data.db" in the current directory for read-only access.
+**          Regardless of whether or not shared-cache mode is enabled by
+**          default, use a private cache.
+** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td>
+**          Open file "/home/fred/data.db". Use the special VFS "unix-nolock".
+** <tr><td> file:data.db?mode=readonly <td> 
+**          An error. "readonly" is not a valid option for the "mode" parameter.
+** </table>
+**
+** ^URI hexadecimal escape sequences (%HH) are supported within the path and
+** query components of a URI. A hexadecimal escape sequence consists of a
+** percent sign - "%" - followed by exactly two hexadecimal digits 
+** specifying an octet value. ^Before the path or query components of a
+** URI filename are interpreted, they are encoded using UTF-8 and all 
+** hexadecimal escape sequences replaced by a single byte containing the
+** corresponding octet. If this process generates an invalid UTF-8 encoding,
+** the results are undefined.
 **
 ** <b>Note to Windows users:</b>  The encoding used for the filename argument
 ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever
@@ -2424,6 +2560,26 @@ SQLITE_API int sqlite3_open_v2(
   const char *zVfs        /* Name of VFS module to use */
 );
 
+/*
+** CAPI3REF: Obtain Values For URI Parameters
+**
+** This is a utility routine, useful to VFS implementations, that checks
+** to see if a database file was a URI that contained a specific query 
+** parameter, and if so obtains the value of the query parameter.
+**
+** The zFilename argument is the filename pointer passed into the xOpen()
+** method of a VFS implementation.  The zParam argument is the name of the
+** query parameter we seek.  This routine returns the value of the zParam
+** parameter if it exists.  If the parameter does not exist, this routine
+** returns a NULL pointer.
+**
+** If the zFilename argument to this function is not a pointer that SQLite
+** passed into the xOpen VFS method, then the behavior of this routine
+** is undefined and probably undesirable.
+*/
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+
+
 /*
 ** CAPI3REF: Error Codes And Messages
 **
@@ -2539,43 +2695,45 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** Additional information is available at [limits | Limits in SQLite].
 **
 ** <dl>
-** ^(<dt>SQLITE_LIMIT_LENGTH</dt>
+** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt>
 ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
+** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt>
 ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_COLUMN</dt>
+** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt>
 ** <dd>The maximum number of columns in a table definition or in the
 ** result set of a [SELECT] or the maximum number of columns in an index
 ** or in an ORDER BY or GROUP BY clause.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
+** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
 ** <dd>The maximum depth of the parse tree on any expression.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
+** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
 ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
+** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt>
 ** <dd>The maximum number of instructions in a virtual machine program
 ** used to implement an SQL statement.  This limit is not currently
 ** enforced, though that might be added in some future release of
 ** SQLite.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
+** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
 ** <dd>The maximum number of arguments on a function.</dd>)^
 **
-** ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
+** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt>
 ** <dd>The maximum number of [ATTACH | attached databases].)^</dd>
 **
+** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]]
 ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt>
 ** <dd>The maximum length of the pattern argument to the [LIKE] or
 ** [GLOB] operators.</dd>)^
 **
+** [[SQLITE_LIMIT_VARIABLE_NUMBER]]
 ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt>
 ** <dd>The maximum index number of any [parameter] in an SQL statement.)^
 **
-** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
+** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
 ** <dd>The maximum depth of recursion for triggers.</dd>)^
 ** </dl>
 */
@@ -3104,7 +3262,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
 ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the
 ** database locks it needs to do its job.  ^If the statement is a [COMMIT]
 ** or occurs outside of an explicit transaction, then you can retry the
-** statement.  If the statement is not a [COMMIT] and occurs within a
+** statement.  If the statement is not a [COMMIT] and occurs within an
 ** explicit transaction then you should rollback the transaction before
 ** continuing.
 **
@@ -3383,7 +3541,7 @@ SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
 ** CAPI3REF: Destroy A Prepared Statement Object
 **
 ** ^The sqlite3_finalize() function is called to delete a [prepared statement].
-** ^If the most recent evaluation of the statement encountered no errors or
+** ^If the most recent evaluation of the statement encountered no errors
 ** or if the statement is never been evaluated, then sqlite3_finalize() returns
 ** SQLITE_OK.  ^If the most recent evaluation of statement S failed, then
 ** sqlite3_finalize(S) returns the appropriate [error code] or
@@ -4610,6 +4768,11 @@ struct sqlite3_module {
                        void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
                        void **ppArg);
   int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
+  /* The methods above are in version 1 of the sqlite_module object. Those 
+  ** below are for version 2 and greater. */
+  int (*xSavepoint)(sqlite3_vtab *pVTab, int);
+  int (*xRelease)(sqlite3_vtab *pVTab, int);
+  int (*xRollbackTo)(sqlite3_vtab *pVTab, int);
 };
 
 /*
@@ -5292,7 +5455,7 @@ struct sqlite3_mutex_methods {
 **
 ** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
 ** the routine should return 1.   This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist.  But the
+** clearly the mutex cannot be held if it does not exist.  But
 ** the reason the mutex does not exist is because the build is not
 ** using mutexes.  And we do not want the assert() containing the
 ** call to sqlite3_mutex_held() to fail, so a non-zero return is
@@ -5415,7 +5578,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 #define SQLITE_TESTCTRL_ISKEYWORD               16
 #define SQLITE_TESTCTRL_PGHDRSZ                 17
 #define SQLITE_TESTCTRL_SCRATCHMALLOC           18
-#define SQLITE_TESTCTRL_LAST                    18
+#define SQLITE_TESTCTRL_LOCALTIME_FAULT         19
+#define SQLITE_TESTCTRL_LAST                    19
 
 /*
 ** CAPI3REF: SQLite Runtime Status
@@ -5424,7 +5588,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
 ** about the performance of SQLite, and optionally to reset various
 ** highwater marks.  ^The first argument is an integer code for
 ** the specific parameter to measure.  ^(Recognized integer codes
-** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
+** are of the form [status parameters | SQLITE_STATUS_...].)^
 ** ^The current value of the parameter is returned into *pCurrent.
 ** ^The highest recorded value is returned in *pHighwater.  ^If the
 ** resetFlag is true, then the highest record value is reset after
@@ -5451,12 +5615,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 
 /*
 ** CAPI3REF: Status Parameters
+** KEYWORDS: {status parameters}
 **
 ** These integer constants designate various run-time status parameters
 ** that can be returned by [sqlite3_status()].
 **
 ** <dl>
-** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
+** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt>
 ** <dd>This parameter is the current amount of memory checked out
 ** using [sqlite3_malloc()], either directly or indirectly.  The
 ** figure includes calls made to [sqlite3_malloc()] by the application
@@ -5466,23 +5631,24 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** this parameter.  The amount returned is the sum of the allocation
 ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
+** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
 ** internal equivalents).  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
+** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
 ** <dd>This parameter records the number of separate memory allocations
 ** currently checked out.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
+** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
 ** <dd>This parameter returns the number of pages used out of the
 ** [pagecache memory allocator] that was configured using 
 ** [SQLITE_CONFIG_PAGECACHE].  The
 ** value returned is in pages, not in bytes.</dd>)^
 **
+** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] 
 ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of page cache
 ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
@@ -5492,13 +5658,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because
 ** no space was left in the page cache.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
+** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [pagecache memory allocator].  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt>
 ** <dd>This parameter returns the number of allocations used out of the
 ** [scratch memory allocator] configured using
 ** [SQLITE_CONFIG_SCRATCH].  The value returned is in allocations, not
@@ -5506,7 +5672,7 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** outstanding at time, this parameter also reports the number of threads
 ** using scratch memory at the same time.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
+** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt>
 ** <dd>This parameter returns the number of bytes of scratch memory
 ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH]
 ** buffer and where forced to overflow to [sqlite3_malloc()].  The values
@@ -5516,13 +5682,13 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** slots were available.
 ** </dd>)^
 **
-** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
 ** <dd>This parameter records the largest memory allocation request
 ** handed to [scratch memory allocator].  Only the value returned in the
 ** *pHighwater parameter to [sqlite3_status()] is of interest.  
 ** The value written into the *pCurrent parameter is undefined.</dd>)^
 **
-** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
+** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
 ** <dd>This parameter records the deepest parser stack.  It is only
 ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
 ** </dl>
@@ -5547,9 +5713,9 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
 ** about a single [database connection].  ^The first argument is the
 ** database connection object to be interrogated.  ^The second argument
 ** is an integer constant, taken from the set of
-** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
+** [SQLITE_DBSTATUS options], that
 ** determines the parameter to interrogate.  The set of 
-** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
+** [SQLITE_DBSTATUS options] is likely
 ** to grow in future releases of SQLite.
 **
 ** ^The current value of the requested parameter is written into *pCur
@@ -5566,6 +5732,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 
 /*
 ** CAPI3REF: Status Parameters for database connections
+** KEYWORDS: {SQLITE_DBSTATUS options}
 **
 ** These constants are the available integer "verbs" that can be passed as
 ** the second argument to the [sqlite3_db_status()] interface.
@@ -5577,15 +5744,16 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** if a discontinued or unsupported verb is invoked.
 **
 ** <dl>
-** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
 ** <dd>This parameter returns the number of lookaside memory slots currently
 ** checked out.</dd>)^
 **
-** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
+** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
 ** <dd>This parameter returns the number malloc attempts that were 
 ** satisfied using lookaside memory. Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]]
 ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt>
 ** <dd>This parameter returns the number malloc attempts that might have
 ** been satisfied using lookaside memory but failed due to the amount of
@@ -5593,6 +5761,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
+** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]]
 ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt>
 ** <dd>This parameter returns the number malloc attempts that might have
 ** been satisfied using lookaside memory but failed due to all lookaside
@@ -5600,12 +5769,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** Only the high-water value is meaningful;
 ** the current value is always zero.)^
 **
-** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
+** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used by all pager caches associated with the database connection.)^
 ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
 **
-** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
+** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** memory used to store the schema for all databases associated
 ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ 
@@ -5614,7 +5783,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** [shared cache mode] being enabled.
 ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
 **
-** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
+** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
 ** <dd>This parameter returns the approximate number of of bytes of heap
 ** and lookaside memory used by all prepared statements associated with
 ** the database connection.)^
@@ -5636,7 +5805,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** CAPI3REF: Prepared Statement Status
 **
 ** ^(Each prepared statement maintains various
-** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
+** [SQLITE_STMTSTATUS counters] that measure the number
 ** of times it has performed specific operations.)^  These counters can
 ** be used to monitor the performance characteristics of the prepared
 ** statements.  For example, if the number of table steps greatly exceeds
@@ -5647,7 +5816,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
 ** ^(This interface is used to retrieve and reset counter values from
 ** a [prepared statement].  The first argument is the prepared statement
 ** object to be interrogated.  The second argument
-** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter]
+** is an integer code for a specific [SQLITE_STMTSTATUS counter]
 ** to be interrogated.)^
 ** ^The current value of the requested counter is returned.
 ** ^If the resetFlg is true, then the counter is reset to zero after this
@@ -5659,24 +5828,25 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
 
 /*
 ** CAPI3REF: Status Parameters for prepared statements
+** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters}
 **
 ** These preprocessor macros define integer codes that name counter
 ** values associated with the [sqlite3_stmt_status()] interface.
 ** The meanings of the various counters are as follows:
 **
 ** <dl>
-** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
 ** <dd>^This is the number of times that SQLite has stepped forward in
 ** a table as part of a full table scan.  Large numbers for this counter
 ** may indicate opportunities for performance improvement through 
 ** careful use of indices.</dd>
 **
-** <dt>SQLITE_STMTSTATUS_SORT</dt>
+** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
 ** <dd>^This is the number of sort operations that have occurred.
 ** A non-zero value in this counter may indicate an opportunity to
 ** improvement performance through careful use of indices.</dd>
 **
-** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
+** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
 ** <dd>^This is the number of rows inserted into transient indices that
 ** were created automatically in order to help joins run faster.
 ** A non-zero value in this counter may indicate an opportunity to
@@ -5727,6 +5897,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** the application may discard the parameter after the call to
 ** [sqlite3_config()] returns.)^
 **
+** [[the xInit() page cache method]]
 ** ^(The xInit() method is called once for each effective 
 ** call to [sqlite3_initialize()])^
 ** (usually only once during the lifetime of the process). ^(The xInit()
@@ -5737,6 +5908,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** built-in default page cache is used instead of the application defined
 ** page cache.)^
 **
+** [[the xShutdown() page cache method]]
 ** ^The xShutdown() method is called by [sqlite3_shutdown()].
 ** It can be used to clean up 
 ** any outstanding resources before process shutdown, if required.
@@ -5751,6 +5923,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^SQLite will never invoke xInit() more than once without an intervening
 ** call to xShutdown().
 **
+** [[the xCreate() page cache methods]]
 ** ^SQLite invokes the xCreate() method to construct a new cache instance.
 ** SQLite will typically create one cache instance for each open database file,
 ** though this is not guaranteed. ^The
@@ -5775,6 +5948,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** ^Hence, a cache created with bPurgeable false will
 ** never contain any unpinned pages.
 **
+** [[the xCachesize() page cache method]]
 ** ^(The xCachesize() method may be called at any time by SQLite to set the
 ** suggested maximum cache-size (number of pages stored by) the cache
 ** instance passed as the first argument. This is the value configured using
@@ -5782,14 +5956,16 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** parameter, the implementation is not required to do anything with this
 ** value; it is advisory only.
 **
+** [[the xPagecount() page cache methods]]
 ** The xPagecount() method must return the number of pages currently
 ** stored in the cache, both pinned and unpinned.
 ** 
+** [[the xFetch() page cache methods]]
 ** The xFetch() method locates a page in the cache and returns a pointer to 
 ** the page, or a NULL pointer.
 ** A "page", in this context, means a buffer of szPage bytes aligned at an
 ** 8-byte boundary. The page to be fetched is determined by the key. ^The
-** mimimum key value is 1.  After it has been retrieved using xFetch, the page 
+** minimum key value is 1.  After it has been retrieved using xFetch, the page 
 ** is considered to be "pinned".
 **
 ** If the requested page is already in the page cache, then the page cache
@@ -5813,6 +5989,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** attempt to unpin one or more cache pages by spilling the content of
 ** pinned pages to disk and synching the operating system disk cache.
 **
+** [[the xUnpin() page cache method]]
 ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
 ** as its second argument.  If the third parameter, discard, is non-zero,
 ** then the page must be evicted from the cache.
@@ -5825,6 +6002,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** call to xUnpin() unpins the page regardless of the number of prior calls 
 ** to xFetch().
 **
+** [[the xRekey() page cache methods]]
 ** The xRekey() method is used to change the key value associated with the
 ** page passed as the second argument. If the cache
 ** previously contains an entry associated with newKey, it must be
@@ -5837,6 +6015,7 @@ typedef struct sqlite3_pcache sqlite3_pcache;
 ** of these pages are pinned, they are implicitly unpinned, meaning that
 ** they can be safely discarded.
 **
+** [[the xDestroy() page cache method]]
 ** ^The xDestroy() method is used to delete a cache allocated by xCreate().
 ** All resources associated with the specified cache should be freed. ^After
 ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
@@ -5899,7 +6078,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** There should be exactly one call to sqlite3_backup_finish() for each
 ** successful call to sqlite3_backup_init().
 **
-** <b>sqlite3_backup_init()</b>
+** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b>
 **
 ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the 
 ** [database connection] associated with the destination database 
@@ -5926,7 +6105,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** sqlite3_backup_finish() functions to perform the specified backup 
 ** operation.
 **
-** <b>sqlite3_backup_step()</b>
+** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
 **
 ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between 
 ** the source and destination databases specified by [sqlite3_backup] object B.
@@ -5983,7 +6162,7 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** by the backup operation, then the backup database is automatically
 ** updated at the same time.
 **
-** <b>sqlite3_backup_finish()</b>
+** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
 **
 ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the 
 ** application wishes to abandon the backup operation, the application
@@ -6006,7 +6185,8 @@ typedef struct sqlite3_backup sqlite3_backup;
 ** is not a permanent error and does not affect the return value of
 ** sqlite3_backup_finish().
 **
-** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b>
+** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]]
+** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b>
 **
 ** ^Each call to sqlite3_backup_step() sets two values inside
 ** the [sqlite3_backup] object: the number of pages still to be backed
@@ -6392,6 +6572,93 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
 #define SQLITE_CHECKPOINT_FULL    1
 #define SQLITE_CHECKPOINT_RESTART 2
 
+/*
+** CAPI3REF: Virtual Table Interface Configuration
+**
+** This function may be called by either the [xConnect] or [xCreate] method
+** of a [virtual table] implementation to configure
+** various facets of the virtual table interface.
+**
+** If this interface is invoked outside the context of an xConnect or
+** xCreate virtual table method then the behavior is undefined.
+**
+** At present, there is only one option that may be configured using
+** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].)  Further options
+** may be added in the future.
+*/
+SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
+
+/*
+** CAPI3REF: Virtual Table Configuration Options
+**
+** These macros define the various options to the
+** [sqlite3_vtab_config()] interface that [virtual table] implementations
+** can use to customize and optimize their behavior.
+**
+** <dl>
+** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported,
+** where X is an integer.  If X is zero, then the [virtual table] whose
+** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not
+** support constraints.  In this configuration (which is the default) if
+** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire
+** statement is rolled back as if [ON CONFLICT | OR ABORT] had been
+** specified as part of the users SQL statement, regardless of the actual
+** ON CONFLICT mode specified.
+**
+** If X is non-zero, then the virtual table implementation guarantees
+** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
+** any modifications to internal or persistent data structures have been made.
+** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite 
+** is able to roll back a statement or database transaction, and abandon
+** or continue processing the current SQL statement as appropriate. 
+** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
+** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
+** had been ABORT.
+**
+** Virtual table implementations that are required to handle OR REPLACE
+** must do so within the [xUpdate] method. If a call to the 
+** [sqlite3_vtab_on_conflict()] function indicates that the current ON 
+** CONFLICT policy is REPLACE, the virtual table implementation should 
+** silently replace the appropriate rows within the xUpdate callback and
+** return SQLITE_OK. Or, if this is not possible, it may return
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT 
+** constraint handling.
+** </dl>
+*/
+#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+
+/*
+** CAPI3REF: Determine The Virtual Table Conflict Policy
+**
+** This function may only be called from within a call to the [xUpdate] method
+** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The
+** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL],
+** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode
+** of the SQL statement that triggered the call to the [xUpdate] method of the
+** [virtual table].
+*/
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
+
+/*
+** CAPI3REF: Conflict resolution modes
+**
+** These constants are returned by [sqlite3_vtab_on_conflict()] to
+** inform a [virtual table] implementation what the [ON CONFLICT] mode
+** is for the SQL statement being evaluated.
+**
+** Note that the [SQLITE_IGNORE] constant is also used as a potential
+** return value from the [sqlite3_set_authorizer()] callback and that
+** [SQLITE_ABORT] is also a [result code].
+*/
+#define SQLITE_ROLLBACK 1
+/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */
+#define SQLITE_FAIL     3
+/* #define SQLITE_ABORT 4  // Also an error code */
+#define SQLITE_REPLACE  5
+
+
 
 /*
 ** Undo the hack that converts floating point types to integer for
index 51818e14671a5b2379a263237f2a0b214ad97b68..e54609eaa1e22c928240b689a476d01f61954d1b 100644 (file)
@@ -7,7 +7,7 @@ includedir=${prefix}/include
 
 Name: SQLite
 Description: SQL database engine
-Version: 3.7.6.2
+Version: 3.7.7.1
 Libs: -L${libdir} -lsqlite3
 Libs.private: -ldl -lpthread 
 Cflags: -I${includedir}
index d2d4c0099cbd783c8bf786e1d7ed71c25b6744b9..948a8bbd1bdfdeac9ad4f5b8141a0a14e6dd6612 100644 (file)
@@ -1,3 +1,3 @@
-Provides: libc libpthread
+Provides: libc libpthread libc_minimal_l4re
 requires: l4sys l4re
 Maintainer: adam@os.inf.tu-dresden.de
index e1c2d083376b3bc04f5012c795e9000a5a3085dc..9742103537728fc188e168fde42305acf9396f5e 100644 (file)
@@ -1,6 +1,6 @@
 PKGDIR ?= ..
 L4DIR  ?= $(PKGDIR)/../..
 
-TARGET = uclibc libpthread
+TARGET = uclibc libpthread minimal_l4re
 
 include $(L4DIR)/mk/subdir.mk
index 75cabee9a3b9545761efae294dd4b8af42373803..c942f9ddbb49affa1bf662cee227eb5df0984164 100644 (file)
@@ -35,9 +35,13 @@ testandset (int *spinlock)
 {
   register unsigned int ret;
 
+#if 0
   __asm__ __volatile__("swp %0, %1, [%2]"
                       : "=r"(ret)
                       : "0"(1), "r"(spinlock));
+#else
+   ret = l4_atomic_xchg((volatile long int *)spinlock, 1);
+#endif
 
   return ret;
 }
diff --git a/l4/pkg/uclibc/lib/minimal_l4re/Makefile b/l4/pkg/uclibc/lib/minimal_l4re/Makefile
new file mode 100644 (file)
index 0000000..65c86a1
--- /dev/null
@@ -0,0 +1,12 @@
+# vi:ft=make
+PKGDIR          ?= ../..
+L4DIR           ?= $(PKGDIR)/../..
+
+TARGET          := libuc_c_minimal_l4re.a
+PC_FILENAME     := libc_minimal_l4re
+DEFINES         := -DL4_MINIMAL_LIBC
+SRC_CC          := _exit.cc
+
+vpath _exit.cc $(SRC_DIR)/../uclibc
+
+include $(L4DIR)/mk/lib.mk
index f533b45cae0bad0bfee68942a28d339ccf6dd429..1001dd024f6b3b517742464a019cfe0f38196e3f 100644 (file)
@@ -30,6 +30,8 @@ $(eval $(call PROCESS_src_lists, $(DIRS), $(SUB_MODULES)))
 # libm stuff
 $(eval $(call PROCESS_template_src, libm, float double))
 
+UCLIBC_SRC_CC             += _exit.cc
+
 SRC_C_libuc_c.so          += $(UCLIBC_SRC_C) $(UCLIBC_SRC_C_libuc_c.so)
 SRC_C_libuc_c.a           += $(UCLIBC_SRC_C) $(UCLIBC_SRC_C_libuc_c.a)
 SRC_S_libuc_c.so          += $(UCLIBC_SRC_S) $(UCLIBC_SRC_S_libuc_c.so)
@@ -52,5 +54,6 @@ CXXFLAGS_$(PTHOBJ_PFX)/sysdeps/generic/libc-tls.cc += -fno-rtti -fno-exceptions
 CPPFLAGS_libc-tls.cc += $(LDSO_INC)
 CPPFLAGS_dl-tls.c += $(LDSO_INC)
 
-.general.d: $(LIBCSRC_DIR_ABS)/Make.rules $(LIBCSRC_DIR)/contrib_files.mk
+$(GENERAL_D_LOC): $(LIBCSRC_DIR_ABS)/Make.rules $(LIBCSRC_DIR)/contrib_files.mk \
+                  $(LIBCSRC_DIR)/make_vars.mk $(LIBCSRC_DIR)/make_rules.mk
 
diff --git a/l4/pkg/uclibc/lib/uclibc/_exit.cc b/l4/pkg/uclibc/lib/uclibc/_exit.cc
new file mode 100644 (file)
index 0000000..d6cdc64
--- /dev/null
@@ -0,0 +1,14 @@
+#include <l4/sys/ipc.h>
+#include <l4/re/env>
+#include <stdlib.h>
+
+extern "C" void _exit(int code)  __attribute__ ((__noreturn__, __weak__));
+
+void _exit(int code)
+{
+  L4Re::Env const *e;
+  if (l4re_global_env && (e = L4Re::Env::env()) && e->parent().is_valid())
+    e->parent()->signal(0, code);
+  for (;;)
+    l4_ipc_sleep(L4_IPC_NEVER);
+}
index 54ec5dbba02563676509cac68d2505f9eba721d8..b2b88bcde74f061bf0a4a7953790c6a243c2453e 100644 (file)
@@ -50,7 +50,7 @@ endef
 add_source_file = $(if $(filter %.c,$(1)),  $(eval $(call add_source_file_x,C$(2),$(1))), \
                   $(if $(filter %.cc,$(1)), $(eval $(call add_source_file_x,CC$(2),$(1))), \
                   $(if $(filter %.S,$(1)),  $(eval $(call add_source_file_x,S$(2),$(1))), \
-                  $(error unkwon source file: $(1)))))
+                  $(error unknown source file: $(1)))))
 
 # generate the search path value for source files
 gen_search_path = $(LIBC_DST_DIR)/$(1)/$(UCLIBC_ARCH) \
@@ -59,8 +59,8 @@ gen_search_path = $(LIBC_DST_DIR)/$(1)/$(UCLIBC_ARCH) \
                   $(LIBC_DST_DIR)/$(1)
 
 # search for a .c, a .S, or a .cc file for the given basename
-search_source_file = $(or $(firstword $(wildcard $(addsuffix /$(2).*,$(1)))), \
-                          $(patsubst %.c,%$(suffix $(2)).c,$(firstword $(wildcard $(addsuffix /$(basename $(2)).*,$(1))))), \
+search_source_file = $(or $(firstword $(foreach d,$(1),$(wildcard $(d)/$(2).[cS] $(d)/$(2).cc))), \
+                          $(patsubst %.c,%$(suffix $(2)).c,$(firstword $(wildcard $(addsuffix /$(basename $(2)).c,$(1))))), \
                           $(error source file for $(2) not found))
 
 # arg 1: directory of the subsystem (e.g., libc/string)
index dfb17f750058bf9d1893c166dc5c147bbd129221..f670d8e5440dac028644c526cd1d4a0e4d147719 100644 (file)
@@ -18,11 +18,11 @@ class Loop_hooks :
     public:
         static L4::Cap<void> rcv_cap;
 
-        static void setup_wait(L4::Ipc_istream &istr, bool before_reply)
+        static void setup_wait(L4::Ipc::Istream &istr, bool before_reply)
         {
             (void)before_reply;
             istr.reset();
-            istr << L4::Small_buf(Vcap::Loop_hooks::rcv_cap.cap(),
+            istr << L4::Ipc::Small_buf(Vcap::Loop_hooks::rcv_cap.cap(),
                                   L4_RCV_ITEM_LOCAL_ID);
             l4_utcb_br()->bdr = 0;
         }
index 4889058bdca2086fe7a8da1e6b6952b57b094da5..aa7f8169e3b1d652dadce779d9d00bb251f46d0e 100644 (file)
@@ -117,16 +117,16 @@ private:
 
 public:
   Region_map();
-  //void setup_wait(L4::Ipc_istream &istr);
-  int handle_pagefault(L4::Ipc_iostream &ios);
-  int handle_rm_request(L4::Ipc_iostream &ios);
+  //void setup_wait(L4::Ipc::Istream &istr);
+  int handle_pagefault(L4::Ipc::Iostream &ios);
+  int handle_rm_request(L4::Ipc::Iostream &ios);
   virtual ~Region_map() {}
 
   void init();
 
   void debug_dump(unsigned long function) const;
 private:
-  int reply_err(L4::Ipc_iostream &ios);
+  int reply_err(L4::Ipc::Iostream &ios);
 };
 
 
index dddf8f39038f358748c38affe82b2e67e77ca474..209f1c0df9eafd3c23b4245737e00c354e4f7632 100644 (file)
@@ -93,7 +93,7 @@ class svr
 
         enum { Have_find = true };
 
-        static int validate_ds(L4::Snd_fpage const & ds_cap, unsigned flags,
+        static int validate_ds(L4::Ipc::Snd_fpage const & ds_cap, unsigned flags,
                                L4::Cap<L4Re::Dataspace> *ds)
         {
             if (dbg_ds) VG_(debugLog)(4, "vcap", "flags 0x%x\n", flags);
@@ -129,7 +129,7 @@ L4::Cap<L4Re::Rm> set_environment_rm(L4::Cap<void> cap)
 class Region_ops
 {
     public:
-        typedef L4::Snd_fpage Map_result;
+        typedef L4::Ipc::Snd_fpage Map_result;
         typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>,
                 Vcap::Rm::Region_ops> MyRegion_handler;
 
@@ -154,7 +154,7 @@ class Region_ops
 
         static int map(MyRegion_handler const *h,
                        l4_addr_t local_addr, L4Re::Util::Region const &r, bool writable,
-                       L4::Snd_fpage *result)
+                       L4::Ipc::Snd_fpage *result)
         {
             int err;
             if (dbg_ds) VG_(debugLog)(4, "vcap", "%s handler %p, local_addr 0x%lx, writable %s\n",
@@ -192,8 +192,8 @@ class Region_ops
 
             if (dbg_ds) VG_(debugLog)(4, "vcap", "ds->map(): %d\n", err);
 
-            *result = L4::Snd_fpage::mem(the_map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
-                                         local_addr, L4::Snd_fpage::Grant);
+            *result = L4::Ipc::Snd_fpage::mem(the_map_area, L4_PAGESHIFT, L4_FPAGE_RWX,
+                                         local_addr, L4::Ipc::Snd_fpage::Grant);
             return L4_EOK;
         }
 
@@ -317,7 +317,7 @@ class rm
 
         rm(unsigned id) : _id(id) { }
 
-        int dispatch(l4_msgtag_t tag, l4_umword_t obj, L4::Ipc_iostream &ios)
+        int dispatch(l4_msgtag_t tag, l4_umword_t obj, L4::Ipc::Iostream &ios)
             throw()
         {
             int err;
@@ -796,7 +796,7 @@ class Vcap_object : public L4::Server_object
             return -L4_EOK;
         }
 
-        int dispatch(l4_umword_t obj, L4::Ipc_iostream &ios) L4_NOTHROW
+        int dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) L4_NOTHROW
         {
             if (dbg_vcap) VG_(debugLog)(4, "vcap", "dispatch\n");
 
index 15758c27e56e6ebc3ce4a040e7ce47bb4bbd06e5..61b27ad7b41327f672dad8316f5f4ac548852210 100755 (executable)
@@ -32,6 +32,7 @@ sub get_file($$)
                                                      $unzip_tmp);
 
   $cmdline =~ s/^\S+\s*//;
+  $cmdline =~ s/,/,,/g;
   $fp.' '.$cmdline;
 }
 
@@ -49,5 +50,18 @@ my $qemu_cmd =
       "-initrd \"$initrd\" ".join(' ', @ARGV);
 
 print "Note: At least QEmu 0.13 is required for the loading to work.\n";
+# and since nobody is reading this message or knows what the version of the
+# installed qemu is...
+my $o = `$qemu -version 2>&1`;
+if ($?)
+  {
+    print "Failed to launch QEmu ($qemu)\n";
+    exit $?;
+  }
+if ($o !~ /\s(\d+)\.(\d+)/ || ($1 == 0 && $2 < 13))
+  {
+    print "\nYour installed Qemu is too old, please upgrade to at least version 0.13.\n\n";
+    exit 1;
+  }
 print "$qemu_cmd\n";
 system("$qemu_cmd");
index 3e3d9b84f5b064e29ad36792de6c74e377f3e945..78f6afc10d20ffcacccf1960db33aa487f8db2d1 100644 (file)
@@ -1,8 +1,8 @@
-VERSION = 2
-PATCHLEVEL = 6
-SUBLEVEL = 39
+VERSION = 3
+PATCHLEVEL = 0
+SUBLEVEL = 0
 EXTRAVERSION =
-NAME = Flesh-Eating Bats with Fangs
+NAME = Sneaky Weasel
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -103,7 +103,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 ifeq ("$(origin W)", "command line")
-  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
 endif
 
 # That's our default target when none is given on the command line
@@ -220,6 +220,14 @@ ifeq ($(ARCH),sh64)
        SRCARCH := sh
 endif
 
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+       SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+       SRCARCH := tile
+endif
+
 # Where to locate arch specific headers
 hdr-arch  := $(SRCARCH)
 
@@ -349,7 +357,8 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
+                   -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
                    -include include/generated/autoconf.h
 
@@ -369,7 +378,7 @@ KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
 
 # Read KERNELRELEASE from include/config/kernel.release (if it exists)
 KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
-KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
 
 export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
 export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
@@ -382,6 +391,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+export KBUILD_ARFLAGS
 
 # When compiling out-of-tree modules, put MODVERDIR in the module
 # tree rather than in the kernel tree. The kernel tree might
@@ -416,6 +426,12 @@ ifneq ($(KBUILD_SRC_disabled_for_fiasco),)
            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
 endif
 
+# Support for using generic headers in asm-generic
+PHONY += asm-generic
+asm-generic:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
+                   obj=arch/$(SRCARCH)/include/generated/asm
+
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
 # It is allowed to specify more targets when calling make, including
@@ -559,6 +575,10 @@ ifndef CONFIG_CC_STACKPROTECTOR
 KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
 endif
 
+# This warning generated too much noise in a regular build.
+# Use make W=1 to enable this warning (see scripts/Makefile.build)
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -604,7 +624,7 @@ CHECKFLAGS     += $(NOSTDINC_FLAGS)
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
 # disable pointer signed / unsigned warnings in gcc 4.0
-KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
@@ -612,6 +632,9 @@ KBUILD_CFLAGS       += $(call cc-option,-fno-strict-overflow)
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
+# use the deterministic mode of AR if available
+KBUILD_ARFLAGS := $(call ar-option,D)
+
 # check for 'asm goto'
 ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
@@ -797,15 +820,17 @@ ifdef CONFIG_KALLSYMS
 # o The correct .tmp_kallsyms2.o is linked into the final vmlinux.
 # o Verify that the System.map from vmlinux matches the map from
 #   .tmp_vmlinux2, just in case we did not generate kallsyms correctly.
-# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# o If 'make KALLSYMS_EXTRA_PASS=1" was used, do an extra pass using
 #   .tmp_vmlinux3 and .tmp_kallsyms3.o.  This is only meant as a
 #   temporary bypass to allow the kernel to be built while the
 #   maintainers work out what went wrong with kallsyms.
 
-ifdef CONFIG_KALLSYMS_EXTRA_PASS
-last_kallsyms := 3
-else
 last_kallsyms := 2
+
+ifdef KALLSYMS_EXTRA_PASS
+ifneq ($(KALLSYMS_EXTRA_PASS),0)
+last_kallsyms := 3
+endif
 endif
 
 kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
@@ -816,7 +841,8 @@ define verify_kallsyms
          $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
        $(Q)cmp -s System.map .tmp_System.map ||                             \
                (echo Inconsistent kallsyms data;                            \
-                echo Try setting CONFIG_KALLSYMS_EXTRA_PASS;                \
+                echo This is a bug - please report about it;                \
+                echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround;      \
                 rm .tmp_kallsyms* ; /bin/false )
 endef
 
@@ -947,7 +973,7 @@ ifneq ($(KBUILD_SRC),)
 endif
 
 # prepare2 creates a makefile if using a separate output directory
-prepare2: prepare3 outputmakefile
+prepare2: prepare3 outputmakefile asm-generic
 
 prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
                    include/config/auto.conf
@@ -979,7 +1005,7 @@ endef
 
 define filechk_version.h
        (echo \#define LINUX_VERSION_CODE $(shell                             \
-       expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL));     \
+       expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL));    \
        echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
 endef
 
@@ -991,7 +1017,8 @@ include/generated/utsrelease.h: include/config/kernel.release FORCE
 
 PHONY += headerdep
 headerdep:
-       $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+       $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
+       $(srctree)/scripts/headerdep.pl -I$(srctree)/include
 
 # ---------------------------------------------------------------------------
 
@@ -1021,7 +1048,7 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
 PHONY += __headers
-__headers: include/linux/version.h scripts_basic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic FORCE
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
@@ -1083,11 +1110,6 @@ modules_install: _modinst_ _modinst_post
 
 PHONY += _modinst_
 _modinst_:
-       @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
-               echo "Warning: you may need to install module-init-tools"; \
-               echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
-               sleep 1; \
-       fi
        @rm -rf $(MODLIB)/kernel
        @rm -f $(MODLIB)/source
        @mkdir -p $(MODLIB)/kernel
@@ -1136,7 +1158,8 @@ CLEAN_FILES +=    vmlinux System.map \
                 .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config usr/include include/generated
+MRPROPER_DIRS  += include/config usr/include include/generated          \
+                  arch/*/include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
@@ -1267,7 +1290,12 @@ help:
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
        @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
-       @echo  '  make W=1   [targets] Enable extra gcc checks'
+       @echo  '  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where'
+       @echo  '                1: warnings which may be relevant and do not occur too often'
+       @echo  '                2: warnings which occur quite often but may still be relevant'
+       @echo  '                3: more obscure warnings, can most likely be ignored'
+       @echo  '                Multiple levels can be combined with W=12 or W=123'
+       @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
        @echo  ''
        @echo  'Execute "make" or "make all" to build all targets marked with [*] '
        @echo  'For further info see the ./README file'
@@ -1290,6 +1318,7 @@ $(help-board-dirs): help-%:
 # Documentation targets
 # ---------------------------------------------------------------------------
 %docs: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts build_docproc
        $(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 else # KBUILD_EXTMOD
@@ -1374,7 +1403,7 @@ endif # KBUILD_EXTMOD
 clean: $(clean-dirs)
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
-       @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+       @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
                \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
@@ -1392,13 +1421,15 @@ tags TAGS cscope gtags: FORCE
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
 
+PHONY += includecheck versioncheck coccicheck namespacecheck export_report
+
 includecheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl
 
 versioncheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
 
@@ -1495,12 +1526,8 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files))
 
 # Run depmod only if we have System.map and depmod is executable
 quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
-      cmd_depmod = \
-       if [ -r System.map -a -x $(DEPMOD) ]; then                              \
-               $(DEPMOD) -ae -F System.map                                     \
-               $(if $(strip $(INSTALL_MOD_PATH)), -b $(INSTALL_MOD_PATH) )     \
-               $(KERNELRELEASE);                                               \
-       fi
+      cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
+                   $(KERNELRELEASE)
 
 # Create temporary dir for module support files
 # clean it up only when building all modules
index 778d26aeeb8df76a4780a4053f0ba8e65352e95c..8f797d724ef625f2c54176f3273daf462ab644ac 100644 (file)
@@ -1,3 +1,3 @@
 
-kconfig taken from vanilla Linux 2.6.39, and slightly patched.
+kconfig taken from vanilla Linux 3.0, and slightly patched.
 
index ed2773edfe71bae99adc0a7b64a454912dfd4477..be39cd1c74cff6009eac1120c1eafe18085ed37e 100644 (file)
@@ -118,6 +118,11 @@ cc-option-yn = $(call try-run,\
 cc-option-align = $(subst -functions=0,,\
        $(call cc-option,-falign-functions=0,-malign-functions=0))
 
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
 # cc-version
 # Usage gcc-ver := $(call cc-version)
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
@@ -141,6 +146,11 @@ cc-ldoption = $(call try-run,\
 ld-option = $(call try-run,\
        $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
 
+# ar-option
+# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
+# Important: no spaces around options
+ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+
 ######
 
 ###
@@ -187,6 +197,8 @@ ifneq ($(KBUILD_NOCMDDEP),1)
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+else
+arg-check = $(if $(strip $(cmd_$@)),,1)
 endif
 
 # >'< substitution is for echo to work,
index fcea26168bca718afb07cf4a2a71081b309e906e..df7678febf277b119cbffc4d3b6f230974fb18f0 100644 (file)
@@ -6,6 +6,7 @@
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
+# docproc:       Used in Documentation/DocBook
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
@@ -16,12 +17,14 @@ hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 always         := $(hostprogs-y) $(hostprogs-m)
 
 # The following hostprogs-y programs are only build on demand
-hostprogs-y += unifdef
+hostprogs-y += unifdef docproc
 
-# This target is used internally to avoid "is up to date" messages
+# These targets are used internally to avoid "is up to date" messages
 PHONY += build_unifdef
 build_unifdef: scripts/unifdef FORCE
        @:
+build_docproc: scripts/docproc FORCE
+       @:
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
index d5f925abe4d29710ab0b314bf28d29752b35dc8d..a0fd5029cfe78c8d082409b3228a59998b15eaa2 100644 (file)
@@ -51,36 +51,52 @@ ifeq ($(KBUILD_NOPEDANTIC),)
 endif
 
 #
-# make W=1 settings
+# make W=... settings
 #
-# $(call cc-option... ) handles gcc -W.. options which
+# W=1 - warnings that may be relevant and does not occur too often
+# W=2 - warnings that occur quite often but may still be relevant
+# W=3 - the more obscure warnings, can most likely be ignored
+#
+# $(call cc-option, -W...) handles gcc -W.. options which
 # are not supported by all versions of the compiler
 ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
-KBUILD_EXTRA_WARNINGS := -Wextra
-KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
-KBUILD_EXTRA_WARNINGS += -Waggregate-return
-KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
-KBUILD_EXTRA_WARNINGS += -Wcast-qual
-KBUILD_EXTRA_WARNINGS += -Wcast-align
-KBUILD_EXTRA_WARNINGS += -Wconversion
-KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
-KBUILD_EXTRA_WARNINGS += -Wlogical-op
-KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
-KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
-KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
-KBUILD_EXTRA_WARNINGS += -Wnested-externs
-KBUILD_EXTRA_WARNINGS += -Wold-style-definition
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
-KBUILD_EXTRA_WARNINGS += -Wpacked
-KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
-KBUILD_EXTRA_WARNINGS += -Wpadded
-KBUILD_EXTRA_WARNINGS += -Wpointer-arith
-KBUILD_EXTRA_WARNINGS += -Wredundant-decls
-KBUILD_EXTRA_WARNINGS += -Wshadow
-KBUILD_EXTRA_WARNINGS += -Wswitch-default
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
-KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
+warning-  := $(empty)
+
+warning-1 := -Wextra -Wunused -Wno-unused-parameter
+warning-1 += -Wmissing-declarations
+warning-1 += -Wmissing-format-attribute
+warning-1 += -Wmissing-prototypes
+warning-1 += -Wold-style-definition
+warning-1 += $(call cc-option, -Wmissing-include-dirs)
+warning-1 += $(call cc-option, -Wunused-but-set-variable)
+
+warning-2 := -Waggregate-return
+warning-2 += -Wcast-align
+warning-2 += -Wdisabled-optimization
+warning-2 += -Wnested-externs
+warning-2 += -Wshadow
+warning-2 += $(call cc-option, -Wlogical-op)
+
+warning-3 := -Wbad-function-cast
+warning-3 += -Wcast-qual
+warning-3 += -Wconversion
+warning-3 += -Wpacked
+warning-3 += -Wpadded
+warning-3 += -Wpointer-arith
+warning-3 += -Wredundant-decls
+warning-3 += -Wswitch-default
+warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
+warning-3 += $(call cc-option, -Wvla)
+
+warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+
+ifeq ("$(strip $(warning))","")
+        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
+endif
+
+KBUILD_CFLAGS += $(warning)
 endif
 
 include scripts/Makefile.lib
@@ -244,14 +260,19 @@ endif
 
 ifdef CONFIG_FTRACE_MCOUNT_RECORD
 ifdef BUILD_C_RECORDMCOUNT
+ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
+  RECORDMCOUNT_FLAGS = -w
+endif
 # Due to recursion, we must skip empty.o.
 # The empty.o file is created in the make process in order to determine
 #  the target endianness and word size. It is made before all other C
 #  files, including recordmcount.
 sub_cmd_record_mcount =                                        \
        if [ $(@) != "scripts/mod/empty.o" ]; then      \
-               $(objtree)/scripts/recordmcount "$(@)"; \
+               $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)";   \
        fi;
+recordmcount_source := $(srctree)/scripts/recordmcount.c \
+                   $(srctree)/scripts/recordmcount.h
 else
 sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
        "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
@@ -259,6 +280,7 @@ sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH
        "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
        "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
        "$(if $(part-of-module),1,0)" "$(@)";
+recordmcount_source := $(srctree)/scripts/recordmcount.pl
 endif
 cmd_record_mcount =                                            \
        if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then    \
@@ -279,13 +301,13 @@ define rule_cc_o_c
 endef
 
 # Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c FORCE
+$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
 
-$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
        @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
@@ -345,7 +367,7 @@ quiet_cmd_link_o_target = LD      $@
 cmd_link_o_target = $(if $(strip $(obj-y)),\
                      $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
                      $(cmd_secanalysis),\
-                     rm -f $@; $(AR) rcs $@)
+                     rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
 
 $(builtin-target): $(obj-y) FORCE
        $(call if_changed,link_o_target)
@@ -371,7 +393,7 @@ $(modorder-target): $(subdir-ym) FORCE
 #
 ifdef lib-target
 quiet_cmd_link_l_target = AR      $@
-cmd_link_l_target = rm -f $@; $(AR) rcs $@ $(lib-y)
+cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
 
 $(lib-target): $(lib-y) FORCE
        $(call if_changed,link_l_target)
index f89cb87f5c018f24b56e13201530df261379c230..a57f5bd5a13d5b8f14a90b03bf23115e925b4a0a 100644 (file)
@@ -27,8 +27,13 @@ header-y      := $(filter-out %/, $(header-y))
 install-file  := $(install)/.install
 check-file    := $(install)/.check
 
+# generic-y list all files an architecture uses from asm-generic
+# Use this to build a list of headers which require a wrapper
+wrapper-files := $(filter $(header-y), $(generic-y))
+
 # all headers files for this dir
-all-files     := $(header-y) $(objhdr-y)
+header-y      := $(filter-out $(generic-y), $(header-y))
+all-files     := $(header-y) $(objhdr-y) $(wrapper-files)
 input-files   := $(addprefix $(srctree)/$(obj)/,$(header-y)) \
                  $(addprefix $(objtree)/$(obj)/,$(objhdr-y))
 output-files  := $(addprefix $(install)/, $(all-files))
@@ -47,6 +52,9 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \
         $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \
+        for F in $(wrapper-files); do                                   \
+                echo "\#include <asm-generic/$$F>" > $(install)/$$F;    \
+        done;                                                           \
         touch $@
 
 quiet_cmd_remove = REMOVE  $(unwanted)
index 1c702ca8aac81d853ac19c204d126c30dff639cb..93b2b5938a2e9e714590ca9728ec53a39763db06 100644 (file)
@@ -197,7 +197,7 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 # ---------------------------------------------------------------------------
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
        (rm -f $@ ; false)
 
 # DTC
index 4c324a1f1e0efb8668b4d64e05b56e8e0f64f25b..4fcef87bb8759894435a395224c7d92cd7a14214 100644 (file)
@@ -7,9 +7,8 @@
 # .config is included by main Makefile.
 # ---------------------------------------------------------------------------
 # fixdep:       Used to generate dependency information during build process
-# docproc:      Used in Documentation/DocBook
 
-hostprogs-y    := fixdep docproc
+hostprogs-y    := fixdep
 always         := $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
index 368ae306aee45a42fbcee26274b491af512afbf0..faa9a4701b6f27259b9f0094aa9ee3584f237fe4 100644 (file)
@@ -77,14 +77,15 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
 # The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
        $(Q)echo "  GEN config"
-       $(Q)xgettext --default-domain=linux              \
-           --add-comments --keyword=_ --keyword=N_      \
-           --from-code=UTF-8                            \
-           --files-from=scripts/kconfig/POTFILES.in     \
+       $(Q)xgettext --default-domain=linux                         \
+           --add-comments --keyword=_ --keyword=N_                 \
+           --from-code=UTF-8                                       \
+           --files-from=$(srctree)/scripts/kconfig/POTFILES.in     \
+           --directory=$(srctree) --directory=$(objtree)           \
            --output $(obj)/config.pot
        $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
-       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
-       $(Q)(for i in `ls arch/*/Kconfig`;               \
+       $(Q)ln -fs Kconfig.x86 arch/um/Kconfig
+       $(Q)(for i in `ls $(srctree)/arch/*/Kconfig`;    \
            do                                           \
                echo "  GEN $$i";                        \
                $(obj)/kxgettext $$i                     \
@@ -92,7 +93,7 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
            done )
        $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
            --output $(obj)/linux.pot
-       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(srctree)/arch/um/Kconfig
        $(Q)rm -f $(obj)/config.pot
 
 PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
@@ -168,8 +169,11 @@ conf-objs  := conf.o  zconf.tab.o
 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
 
-hostprogs-y := conf qconf gconf kxgettext
+hostprogs-y := conf
 
 ifeq ($(MAKECMDGOALS),nconfig)
        hostprogs-y += nconf
@@ -179,6 +183,10 @@ ifeq ($(MAKECMDGOALS),menuconfig)
        hostprogs-y += mconf
 endif
 
+ifeq ($(MAKECMDGOALS),update-po-config)
+       hostprogs-y += kxgettext
+endif
+
 ifeq ($(MAKECMDGOALS),xconfig)
        qconf-target := 1
 endif
@@ -188,16 +196,15 @@ endif
 
 
 ifeq ($(qconf-target),1)
-qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
+       hostprogs-y += qconf
 endif
 
 ifeq ($(gconf-target),1)
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+       hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
-                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    += zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 
@@ -321,11 +328,12 @@ $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
 $(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
 
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
-       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+       $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+       $(obj)/gconf.glade
 
 ###
 # The following requires flex/bison/gperf
index 6364981e9819e833e14f4a09224559337614f489..f6b5d64005f753ed97d2f90de360c29d91725ab2 100644 (file)
@@ -560,8 +560,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       time_t now;
-       int use_timestamp = 1;
        char *env;
 
        dirname[0] = 0;
@@ -598,19 +596,11 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       time(&now);
-       env = getenv("KCONFIG_NOTIMESTAMP");
-       if (env && *env)
-               use_timestamp = 0;
-
        fprintf(out, _("#\n"
                       "# Automatically generated make config: don't edit\n"
                       "# %s\n"
-                      "%s%s"
                       "#\n"),
-                    rootmenu.prompt->text,
-                    use_timestamp ? "# " : "",
-                    use_timestamp ? ctime(&now) : "");
+                    rootmenu.prompt->text);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -784,7 +774,6 @@ int conf_write_autoconf(void)
        const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
-       time_t now;
        int i;
 
        sym_clear_all_valid();
@@ -811,22 +800,19 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       time(&now);
        fprintf(out, "#\n"
                     "# Automatically generated make config: don't edit\n"
                     "# %s\n"
-                    "# %s"
                     "#\n",
-                    rootmenu.prompt->text, ctime(&now));
+                    rootmenu.prompt->text);
        fprintf(tristate, "#\n"
                          "# Automatically generated - do not edit\n"
                          "\n");
        fprintf(out_h, "/*\n"
                       " * Automatically generated C config: don't edit\n"
                       " * %s\n"
-                      " * %s"
                       " */\n",
-                      rootmenu.prompt->text, ctime(&now));
+                      rootmenu.prompt->text);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
index 3d238db4976405fee6aa122c3582e4a717a25315..16bfae2d321742bd5bf06e0a17e3e6377b47ef71 100644 (file)
@@ -20,12 +20,8 @@ struct file {
        struct file *parent;
        const char *name;
        int lineno;
-       int flags;
 };
 
-#define FILE_BUSY              0x0001
-#define FILE_SCANNED           0x0002
-
 typedef enum tristate {
        no, mod, yes
 } tristate;
index 295e9c98ed1ea2cdab5b55c9e21f8992ef65c76b..a8000d779451986267224f3f6d51b10470961405 100644 (file)
@@ -253,7 +253,7 @@ void init_left_tree(void)
 
        gtk_tree_view_set_model(view, model1);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -298,7 +298,7 @@ void init_right_tree(void)
 
        gtk_tree_view_set_model(view, model2);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -756,7 +756,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = SINGLE_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        current = &rootmenu;
        display_tree_part();
@@ -782,7 +781,6 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = FULL_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        if (tree2)
                gtk_tree_store_clear(tree2);
@@ -1444,6 +1442,12 @@ static void display_tree(struct menu *menu)
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW))*/
+
+               /* Change paned position if the view is not in 'split mode' */
+               if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+                       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+               }
+
                if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW)) {
index 6eb039718259a38838268c7df29a2212cb265bed..d9182916f72494d3138a93a352f24a11ee3f06e7 100644 (file)
@@ -2363,11 +2363,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -2383,18 +2383,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -2404,8 +2411,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index db56377393d7922229562fa1ea767f3288424e25..488dd741078747132b08dc9afb33001f4a03db5a 100644 (file)
@@ -373,18 +373,18 @@ static void print_function_line(void)
        const int skip = 1;
 
        for (i = 0; i < function_keys_num; i++) {
-               wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+               (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
                mvwprintw(main_window, LINES-3, offset,
                                "%s",
                                function_keys[i].key_str);
-               wattrset(main_window, attributes[FUNCTION_TEXT]);
+               (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
                offset += strlen(function_keys[i].key_str);
                mvwprintw(main_window, LINES-3,
                                offset, "%s",
                                function_keys[i].func);
                offset += strlen(function_keys[i].func) + skip;
        }
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 }
 
 /* help */
@@ -953,16 +953,16 @@ static void show_menu(const char *prompt, const char *instructions,
        current_instructions = instructions;
 
        clear();
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
        print_in_middle(stdscr, 1, 0, COLS,
                        menu_backtitle,
                        attributes[MAIN_HEADING]);
 
-       wattrset(main_window, attributes[MAIN_MENU_BOX]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
        box(main_window, 0, 0);
-       wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
        mvwprintw(main_window, 0, 3, " %s ", prompt);
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 
        set_menu_items(curses_menu, curses_menu_items);
 
index 06dd2e33581de5de81863bd1b74b2fb7100af5ed..c2796b866f8f14a37453f409429b900e1f11ba44 100644 (file)
@@ -1489,8 +1489,7 @@ void ConfigMainWindow::saveConfigAs(void)
        QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
-       if (conf_write(QFile::encodeName(s)))
-               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+       saveConfig();
 }
 
 void ConfigMainWindow::searchConfig(void)
@@ -1643,7 +1642,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               conf_write(NULL);
+               saveConfig();
        case QMessageBox::No:
                e->accept();
                break;
index 3dbaec185cc486d183ed5ba87cfe848635e4b968..b22f884f90221650ed46ef4cf509bf6a3b33170e 100644 (file)
@@ -294,11 +294,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -314,18 +314,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -335,8 +342,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;