config CAN_ARM_CPU_CORTEX_A9
bool
+config CAN_ARM_CACHE_L2CXX0
+ bool
choice
prompt "CPU"
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
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.
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
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
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
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)
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
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;
{
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;
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)
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
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)
bool "PB11MP"
depends on PF_REALVIEW
select CAN_ARM_CPU_MPCORE
+ select CAN_ARM_CACHE_L2CXX0
help
Choose for PB11MP
bool "PBX"
depends on PF_REALVIEW
select CAN_ARM_CPU_CORTEX_A9
+ select CAN_ARM_CACHE_L2CXX0
help
Choose for PBX-A9.
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
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)
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,
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,
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,
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,
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,
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,
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 {
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,
};
};
-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);
}
// ------------------------------------------------------------------------
-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
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);
# 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
reset_IMPL += reset-arm-tegra2
clock_IMPL += clock-generic
boot_mp_IMPL += boot_mp-arm-tegra2
+outer_cache_IMPL += outer_cache-arm-tegra2
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,
--- /dev/null
+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);
+}
INTERFACE [arm && tegra2]:
#include "gic.h"
-#include "kmem.h"
class Irq_base;
#include "initcalls.h"
#include "irq_chip.h"
#include "irq_chip_generic.h"
+#include "kmem.h"
Gic Gic_pin::_gic[1];
};
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);
}
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()
{}
//---------------------------------------------------------------------------
bool _ignore_mem_op_in_progess;
};
+// ------------------------------------------------------------------------
+INTERFACE [armv6plus]:
+
+EXTENSION class Context
+{
+private:
+ Mword _tpidrurw;
+};
+
// ------------------------------------------------------------------------
IMPLEMENTATION [arm]:
: "=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();
// switch to our page directory if nessecary
vcpu_aware_space()->switchin_context(from->vcpu_aware_space());
+ load_tpidrurw();
+
Utcb_support::current(utcb().usr());
}
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
+{}
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; }
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;
};
// ------------------------------------------------------------------------
{
public:
struct Exception_state_user
- {
- };
-};
-
-// ------------------------------------------------------------------------
-INTERFACE [arm]:
-
-EXTENSION class Fpu
-{
-public:
- enum Fpu_exception_returns
- {
- Fpu_except_none,
- Fpu_except_emulated,
- Fpu_except_fault,
- };
+ {
+ };
};
// ------------------------------------------------------------------------
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]:
#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
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;
}
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;
}
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;
}
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"
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)
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
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;
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()
_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];
};
--- /dev/null
+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);
+}
{
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
+ ,
};
};
_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");
}
}
}
}
-PUBLIC /*inline*/
+//-----------------------------------------------------------------------------
+IMPLEMENTATION [armv6 || armca8]:
+
+PUBLIC
void Page_table::activate(unsigned long asid)
{
Pte p = walk(this, 0, false, 0);
_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");
}
}
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);
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();
}
-
!= 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" {
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;
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]:
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);
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
.long MPCORE_PHYS_BASE
// only one currently
-.Lactrl_cpuid:
+.Lactrl_cpuid_a9:
.long 0xff0ffff0
.long 0x410fc090
unsigned Config::tbuf_entries = 0x20000 / sizeof(Mword); //1024;
//-----------------------------------------------------------------------------
-IMPLEMENTATION [!arm && !ppc32]:
+IMPLEMENTATION:
IMPLEMENT FIASCO_INIT
void Config::init()
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);
-}
-
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);
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));
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);
}
//---------------------------------------------------------------------------
INTERFACE[ia32,ux]:
#include "initcalls.h"
+#include "std_macros.h"
class Kernel_thread;
INTERFACE[amd64]:
#include "initcalls.h"
+#include "std_macros.h"
class Kernel_thread;
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))
{
Apic *_apic;
Spin_lock<> _l;
unsigned _offset;
+ unsigned _irqs;
static Io_apic _apics[Max_ioapics];
static unsigned _nr_irqs;
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,
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();
}
Io_apic::total_irqs()
{ return _nr_irqs; }
-PUBLIC static
+PUBLIC static
unsigned
Io_apic::legacy_override(unsigned i)
{
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",
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
{
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;
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;
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()
{}
"Kpreempt",
"Ksysexc",
"Kexc", // -5
- "Ks0",
+ "Ksigma",
0,
"Kiopf",
"Kcapfault",
receiver()->vcpu_update_state();
set_receiver(0);
- remote_ready_enqueue();
+ // remote_ready_enqueue(): is only for mp
+ activate();
}
PUBLIC inline
l->cap_idx = _exc_handler.raw());
if (EXPECT_FALSE(space() == sigma0_task))
{
+ ts->dump();
WARNX(Error, "Sigma0 raised an exception --> HALT\n");
panic("...");
}
-/** 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)
Kobject::destroy(rl);
check_kdb(kill());
assert_kdb(_magic == magic);
-
}
PUBLIC
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];
+};
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_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
#
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_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
#
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
#
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
# 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
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
#
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
#
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
#
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
# 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
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
#
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
#
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
#
-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"
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
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)
# 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
# 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
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
$(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
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
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)
# 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
# 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
$(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
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
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
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
# ---------------------------------------------------------------------------
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
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
.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
@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'
# Documentation targets
# ---------------------------------------------------------------------------
%docs: scripts_basic FORCE
+ $(Q)$(MAKE) $(build)=scripts build_docproc
$(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # 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' \
# 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
# 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
-kconfig taken from vanilla Linux 2.6.39, and slightly patched.
+kconfig taken from vanilla Linux 3.0, and slightly patched.
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))
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))
+
######
###
# 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,
# 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
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
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
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)" \
"$(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 \
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)
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)
#
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)
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))
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)
# ---------------------------------------------------------------------------
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
# .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
# 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 \
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
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
hostprogs-y += mconf
endif
+ifeq ($(MAKECMDGOALS),update-po-config)
+ hostprogs-y += kxgettext
+endif
+
ifeq ($(MAKECMDGOALS),xconfig)
qconf-target := 1
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
$(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
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;
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();
const char *str;
const char *name;
FILE *out, *tristate, *out_h;
- time_t now;
int i;
sym_clear_all_valid();
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);
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;
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);
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);
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();
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);
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)) {
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));
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;
{
struct buffer *parent;
- current_file->flags |= FILE_SCANNED;
- current_file->flags &= ~FILE_BUSY;
current_file = current_file->parent;
parent = current_buf->parent;
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 */
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);
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)
mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
switch (mb.exec()) {
case QMessageBox::Yes:
- conf_write(NULL);
+ saveConfig();
case QMessageBox::No:
e->accept();
break;
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));
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;
{
struct buffer *parent;
- current_file->flags |= FILE_SCANNED;
- current_file->flags &= ~FILE_BUSY;
current_file = current_file->parent;
parent = current_buf->parent;
$(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
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)
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
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
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)
-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
CONFIG_BUILD_ABI_l4f=y
CONFIG_BUILD_ABI="l4f"
CONFIG_CPU="603e"
+CONFIG_RAM_BASE=0x0
+CONFIG_RAM_SIZE_MB=64
#
# Platform
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
endif # called for static
+# ----------------------------------------------------
ifeq ($(CALLED_FOR),shared)
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)
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
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 =
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) \
#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>
assert(false);
}
- L4::Ipc_iostream s(l4_utcb());
+ L4::Ipc::Iostream s(l4_utcb());
s << l4_umword_t(Ankh::Opcode::Activate);
#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>
assert(false);
}
- L4::Ipc_iostream s(l4_utcb());
+ L4::Ipc::Iostream s(l4_utcb());
s << l4_umword_t(Ankh::Opcode::Activate);
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())
-lwip 1.3.1
+lwip git master
+commit 17efa04ea686f81ebdbf51363bdec5886e03a51c
+Date: Tue Aug 9 13:55:40 2011 -0600
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 \
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 \
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 \
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?");
struct ankhif *ankhif;
struct eth_hdr *ethhdr;
struct pbuf *p;
+ int x;
ankhif = netif->state;
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;
break;
default:
+ printf("unknown ethtype %lx\n", htons(ethhdr->type));
pbuf_free(p);
p = NULL;
break;
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);
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
+#if LWIP_TCP
struct api_msg msg;
err_t err;
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 */
}
/**
#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;
#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
return ERR_CLSD;
}
len = ((struct pbuf *)buf)->tot_len;
- }
+ }
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
{
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));
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);
}
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 */
if (buf == NULL) {
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM;
- }
+ }
err = netconn_recv_data(conn, (void **)&p);
if (err != ERR_OK) {
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;
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. */
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 */
}
/**
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);
}
* - 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;
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;
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);
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.
*
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
/**
#include "lwip/tcpip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
+#include "lwip/mld6.h"
#include <string.h>
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;
}
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;
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);
}
} 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 */
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);
}
/* 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);
}
/* 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 */
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 {
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 */
}
/**
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);
}
/**
conn->socket = -1;
#endif /* LWIP_SOCKET */
conn->callback = callback;
- conn->recv_avail = 0;
#if LWIP_TCP
conn->current_msg = NULL;
conn->write_offset = 0;
#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;
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
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);
}
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;
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 {
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 */
(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",
/* 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);
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);
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);
/* 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);
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) {
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;
}
}
default:
LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
break;
- }
+ }
}
sys_sem_signal(&msg->conn->op_completed);
}
TCPIP_APIMSG_ACK(msg);
}
+#if LWIP_TCP
/**
* Set a TCP pcb contained in a netconn into listen mode
* Called from netconn_listen.
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);
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;
}
}
}
-#endif /* LWIP_TCP */
TCPIP_APIMSG_ACK(msg);
}
+#endif /* LWIP_TCP */
/**
* Send some data on a RAW or UDP pcb contained in a netconn
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;
TCPIP_APIMSG_ACK(msg);
}
+#if LWIP_TCP
/**
* Indicate data has been received from a TCP pcb contained in a netconn
* Called from netconn_recv
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;
}
}
}
-#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
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;
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) {
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;
}
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
/* @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 */
{
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
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)
}
TCPIP_APIMSG_ACK(msg);
}
-#endif /* LWIP_IGMP */
+#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
"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 */
};
/**
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
#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;
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);
/* 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;
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));
#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 */
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 */
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 */
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 \
#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); \
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;
{
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);
/* 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);
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;
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));
}
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);
}
{
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) {
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));
}
/* 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);
s, lwip_strerr(err)));
sock_set_errno(sock, err_to_errno(err));
if (err == ERR_CLSD) {
- return 0;
+ return 0;
} else {
return -1;
}
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;
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) ||
/* 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);
}
}
/* 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));
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);
}
} 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);
}
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));
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
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);
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 */
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();
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 */
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);
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) {
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;
}
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);
*readset_out = lreadset;
*writeset_out = lwriteset;
*exceptset_out = lexceptset;
-
+
LWIP_ASSERT("nready >= 0", nready >= 0);
return nready;
}
*/
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;
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
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) {
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)) ||
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 */
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 */
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);
if (exceptset) {
*exceptset = lexceptset;
}
-
-
return nready;
}
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);
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);
}
/**
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;
}
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;
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:
}
/* 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) {
}
/* 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;
}
/* 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;
optval = data->optval;
switch (level) {
-
+
/* Level: SOL_SOCKET */
case SOL_SOCKET:
switch (optname) {
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;
*(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;
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);
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;
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;
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;
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;
}
/* 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) {
}
/* 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) {
/* 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;
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:
{
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;
/* 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;
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;
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.
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);
}
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));
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);
#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 */
}
#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
#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.
@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)
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);
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 */
}
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.
*
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);
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;
}
/* 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));
}
}
/* 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
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
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
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;
/* 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) {
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)) {
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 */
* 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;
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);
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;
}
/* 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;
}
* 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
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
--- /dev/null
+/**
+ * @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) */
#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.
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()
/* Modules initialization */
stats_init();
+#if !NO_SYS
sys_init();
+#endif /* !NO_SYS */
mem_init();
memp_init();
pbuf_init();
#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 */
}
/* 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.
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
*/
/* 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
*/
("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"));
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);
}
}
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,
struct autoip *autoip = netif->autoip;
err_t result = ERR_OK;
- if(netif_is_up(netif)) {
+ if (netif_is_up(netif)) {
netif_set_down(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"));
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;
* 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;
}
}
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--;
}
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;
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.
*
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),
*/
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).
!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:
* 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
#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;
}
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 */
/* 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);
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));
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,
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);
}
*/
#define IGMP_TTL 1
#define IGMP_MINLEN 8
-#define ROUTER_ALERT 0x9404
+#define ROUTER_ALERT 0x9404U
#define ROUTER_ALERTLEN 4
/*
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
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);
}
/* 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);
/**
* 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;
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"));
}
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 */
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);
}
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)));
}
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);
}
}
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
*
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);
--- /dev/null
+/**
+ * @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 */
--- /dev/null
+/**
+ * @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;
+}
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);
#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 */
/**
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 */
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;
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.
*/
left_to_copy -= newpbuflen;
if (left_to_copy) {
p = p->next;
- }
+ }
}
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
--- /dev/null
+/**
+ * @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 */
--- /dev/null
+/**
+ * @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(ðhdr->dest, dst, 6);
+ SMEMCPY(ðhdr->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 */
+/**
+ * @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 */
/**
* @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 */
+/**
+ * @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 */
+/**
+ * @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 */
--- /dev/null
+/**
+ * @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 */
--- /dev/null
+/**
+ * @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 */
--- /dev/null
+/**
+ * @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 */
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
/* 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;
}
/**
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)));
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
#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>
#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)
struct netif *netif_list;
struct netif *netif_default;
+static u8_t netif_num;
+
#if LWIP_HAVE_LOOPIF
static struct netif loop_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);
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 */
/* 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 */
#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;
/* 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 */
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);
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 */
}
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);
}
}
}
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 */
+
}
}
}
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
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 */
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) {
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);
}
}
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);
}
}
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 */
}
#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 */
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
* 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).
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);
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.
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 */
/**
* 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
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);
+}
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
+#include "lwip/ip6.h"
+#include "lwip/ip6_addr.h"
#include <string.h>
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;
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;
}
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;
}
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;
}
{
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? */
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);
}
#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) {
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));
}
/**
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 */
#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"
/**
#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);
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;
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
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++;
{
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;
{
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 */
/* 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.
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);
}
/**
#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));
#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));
#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));
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 */
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();
#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",
/* 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. */
/* 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);
* 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;
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 */
} 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 */
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);
}
}
* 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
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,
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) {
/* 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
((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);
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;
}
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;
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
{
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 );
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;
}
{
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();
}
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;
}
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 */
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
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 */
}
/* 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;
/* 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);
/* 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);
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;
/* 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);
/* 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);
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;
}
}
- /* 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);
#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
*/
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
- }
+ }
}
/**
LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
(void *)inactive, inactivity));
tcp_abort(inactive);
- }
+ }
}
/**
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.
*/
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
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;
}
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;
}
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;
}
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 */
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 */
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);
* 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.
#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;
* 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
#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. */
/* 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. */
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). */
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. */
}
}
- /* 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;
}
}
#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
/* Set up a tcp_seg structure. */
inseg.next = NULL;
inseg.len = p->tot_len;
- inseg.dataptr = p->payload;
inseg.p = p;
inseg.tcphdr = tcphdr;
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;
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 */
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:
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);
}
/**
/* 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
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;
/* 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();
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.*/
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;
}
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;
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
/* 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:
* the connection. */
/* Already aborted? */
if (err != ERR_ABRT) {
- tcp_abort(pcb);
+ tcp_abort(pcb);
}
return ERR_ABRT;
}
}
} 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 */
/* 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);
- }
- }
+ }
+ }
}
}
}
}
} 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. */
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;
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;
}
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.
/* 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);
/*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
#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>
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;
}
* 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.
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;
/* 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.
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 */
/* 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 */
} 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,
#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. */
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) {
#if TCP_OVERSIZE_DBGCHECK
last_unsent->oversize_left -= oversize_used;
#endif /* TCP_OVERSIZE_DBGCHECK */
- }
+ }
pcb->unsent_oversize = oversize;
#endif /* TCP_OVERSIZE */
* is harmless
*/
if (last_unsent == NULL) {
- pcb->unsent = queue;
+ pcb->unsent = queue;
} else {
last_unsent->next = queue;
- }
+ }
/*
* Finally update the pcb state.
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. */
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,
return ERR_OK;
}
-
#if LWIP_TCP_TIMESTAMPS
/* Build a timestamp option (12 bytes long) at the specified options pointer)
*
#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;
}
/**
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
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. */
/* 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);
}
#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) {
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",
}
/* 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);
#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*/
}
* @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;
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));
}
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));
}
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);
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
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"));
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);
#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;
}
#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)
{
#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 */
* - 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;
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) {
* 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;
}
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) {
{
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) {
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) {
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 */
{
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) {
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();
}
#endif /* NO_SYS */
+
+#else /* LWIP_TIMERS */
+/* Satisfy the TCP code which calls this function */
+void
+tcp_timer_needed(void)
+{
+}
+#endif /* LWIP_TIMERS */
#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"
* 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.
*
*/
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));
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));
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;
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;
}
}
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) &&
}
/* 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
}
/* 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) {
} 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);
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);
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);
+ }
}
}
}
}
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);
} 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();
}
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");
}
/**
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
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 */
{
#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;
}
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;
/* 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;
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));
/* 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 */
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));
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 */
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();
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;
/* 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));
}
}
- 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;
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
- }
+ }
}
if (ipcb != NULL) {
/* no more ports available in local range */
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.
*
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) {
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;
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;
}
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.
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 */
};
-/** 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);
#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 3 /* 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 */
};
#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
#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)
--- /dev/null
+/*
+ * 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__ */
+
+
--- /dev/null
+/*
+ * 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__ */
#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 */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
+
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
--- /dev/null
+/**
+ * @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__ */
*/
/* 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) */
/* 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
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;
/** 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
#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)
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);
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) { \
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.
*/
} bc;
/** used for do_getaddr */
struct {
- ip_addr_t *ipaddr;
+ ipX_addr_t *ipaddr;
u16_t *port;
u8_t local;
} ad;
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;
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);
#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;
#define __LWIP_DEBUG_H__
#include "lwip/arch.h"
+#include "lwip/opt.h"
/** lower two bits indicate debug level
* - 0 all
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]);
#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)*/
#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
#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
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__ */
#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 -8 /* Connection aborted. */
-#define ERR_RST -9 /* 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
--- /dev/null
+/*
+ * 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__ */
+
/** 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) */
--- /dev/null
+/*
+ * 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__ */
+
+
--- /dev/null
+/*
+ * 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__ */
/* 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
#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")
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")
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.
*
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
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
#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 */
};
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);
#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
(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
#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
lwip_getaddrinfo(nodname, servname, hints, res)
#endif /* LWIP_COMPAT_SOCKETS */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* LWIP_DNS && LWIP_SOCKET */
#endif /* __LWIP_NETDB_H__ */
#include "lwip/err.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#if LWIP_AUTOIP
struct autoip;
#endif
+#if LWIP_IPV6_DHCP6
+#include "lwip/dhcp6.h"
+#endif /* LWIP_IPV6_DHCP6 */
#ifdef __cplusplus
extern "C" {
*/
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.
*
/** 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
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;
* 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
*/
/** 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;
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 */
#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
#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__ */
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,
/** 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 */
/** 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.
* 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;
* 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);
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
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
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;
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;
};
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. */
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
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
+#include "lwip/inet6.h"
#ifdef __cplusplus
extern "C" {
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
#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
#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
#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;
#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()
#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)
#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" {
*/
#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
/* 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 */
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. */
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 */
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
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
}
#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" {
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
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);
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
/** 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
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);
TCPIP_MSG_TIMEOUT,
TCPIP_MSG_UNTIMEOUT,
#endif /* LWIP_TCPIP_TIMEOUT */
- TCPIP_MSG_CALLBACK
+ TCPIP_MSG_CALLBACK,
+ TCPIP_MSG_CALLBACK_STATIC
};
struct tcpip_msg {
#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" {
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);
}
#endif
+#endif /* LWIP_TIMERS */
#endif /* __LWIP_TIMERS_H__ */
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
+#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
# 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;
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 */
#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;
};
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);
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. */
#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
* 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
/** 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. */
#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
#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
#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
#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.
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];
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)) \
#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))
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;
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 */
}
}
* 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
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 */
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;
}
/* 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);
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;
}
* @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;
#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 */
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;
}
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
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 */
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;
{
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
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;
}
/* 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 */
#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) {
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 */
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);
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 */
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.
*
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) {
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. */
/* 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);
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 */
}
/* 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) {
/* { 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)) {
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;
}
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? */
* 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(ðhdr->dest, ethdst_hwaddr);
#else /* LWIP_AUTOIP */
{
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;
#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 */
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(ðhdr->dest, ðbroadcast)) {
+ /* mark the pbuf as link-layer broadcast */
+ p->flags |= PBUF_FLAG_LLBCAST;
+ }
+ }
+
switch (type) {
#if LWIP_ARP
/* IP packet? */
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 {
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);
#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"
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
+ case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
* 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]);
{
int i;
struct protent *protp;
-
+
AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit));
if (did_authup) {
return;
}
}
-
+
lcp_phase[unit] = PHASE_AUTHENTICATE;
auth = 0;
#if CHAP_SUPPORT
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:
AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol));
return;
}
-
+
/*
* Save the authenticated name of the peer for later.
*/
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));
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:
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.
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.
-
-
-
+
+
+
free_wordlist(struct wordlist *wp)
{
struct wordlist *next;
-
+
while (wp != NULL) {
next = wp->next;
free(wp);
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) {
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 ||
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) {
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);
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);
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));
}
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)
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);
{
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 */
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;
int code, id, len;
int clen, nlen;
u_char x;
-
+
if (plen < CHAP_HEADERLEN) {
return 0;
}
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]));
}
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]));
/*
* 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. */
goto bad;
}
return (1);
-
+
bad:
IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n"));
return (0);
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 */
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;
case ECHOREP:
lcp_received_echo_reply(f, id, inp, len);
break;
-
+
case DISCREQ:
break;
-
+
default:
return 0;
}
LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n"));
return;
}
-
+
/* Reset the number of outstanding echo frames */
lcp_echos_pending = 0;
}
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;
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;
}
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 */
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 */
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) {
magicInit();
- subnetMask = PP_HTONL(0xffffff00);
+ subnetMask = PP_HTONL(0xffffff00UL);
for (i = 0; i < NUM_PPP; i++) {
/* Initialize each protocol to the standard option set. */
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
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 */
}
#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;
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);
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;
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. */
/* update the frame check sequence number. */
pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar);
- }
+ }
} /* while (l-- > 0), all bytes processed */
avRandomize();
#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
* @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)
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;
}
/* 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)) {
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;
*/
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;
}
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
#include "device"
#include <cstring>
#include <cstdio>
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));
}
#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>
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;
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;
}
else
{
- L4::cerr << "Error creating Ankh session object.\n";
+ std::cerr << "Error creating Ankh session object.\n";
return -L4_ENOMEM;
}
}
}
catch (L4::Base_exception const &e)
{
- L4::cerr << "Error: " << e << '\n';
+ std::cerr << "Error: " << e << '\n';
return -1;
}
catch (std::exception const &e)
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,
ENTRY(_start)
PHDRS {
- data PT_LOAD;
+ common PT_LOAD;
#ifdef IMAGE_MODE
mods PT_LOAD;
#endif
{
. = 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.*)
. = ALIGN(4096);
_modules_end = .;
- } : data
+ } : common
+
_edata = .;
PROVIDE (edata = .);
. = ALIGN(4096);
*(.bss)
*(COMMON)
*(.bss_memmap)
- } : data
+ } : common
_end = . ;
PROVIDE (end = .);
#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
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)
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
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
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 \
$(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
static L4::Uart *stdio_uart;
-L4::Uart *uart()
+L4::Uart *uart()
{ return stdio_uart; }
void set_stdio_uart(L4::Uart *uart)
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;
#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);
#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
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/**
+ * \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);
--- /dev/null
+/**
+ * \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);
--- /dev/null
+/**
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
--- /dev/null
+/*!
+ * \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);
+
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 */
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../..
-EXTRA_TARGET := exceptions string
+EXTRA_TARGET := exceptions string std_exc_io
include $(L4DIR)/mk/include.mk
--- /dev/null
+// 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;
+}
* \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
{
* 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()).
*
* 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 >
* \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 >
#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
// 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);
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
// 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);
{
// 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);
}
// 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;
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;
#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;
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);
/**
* 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;
/**
* 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",
/*** 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];
/*** 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];
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;
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;
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) {}
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
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);
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);
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);
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);
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);
}
*
* return 0 on success, != 0 otherwise
*/
-long dope_init(void)
+L4_CV long dope_init(void)
{
static int initialized;
long ds_size;
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))
#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>
{
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)
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));
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);
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
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;
};
}
-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;
{
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);
};
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;
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;
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;
}
};
--- /dev/null
+/*
+ * (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
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
--- /dev/null
+/*
+ * (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;
+ }
+};
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
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()))
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()))
#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"
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;
/**
* 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
* 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
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;
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
#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"
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;
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:
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
~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);
}
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;
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(); }
}
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;
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;
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;
}
};
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
{
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;
}
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;
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;
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)
{
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 {
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;
};
}
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;
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;
{
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);
};
/** 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);
#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;
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);
return 0;
}
-int l4input_pcspkr(int tone)
+L4_CV int l4input_pcspkr(int tone)
{
if (ops->pcspkr)
return ops->pcspkr(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");
/** 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)
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 */
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)
{
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;
# Please see the COPYING-GPL-2 file for details.
-// multi-core EB
+# multi-core EB (PB11MP)
hw-root
{
CTRL => new Device()
--- /dev/null
+# 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);
+ }
+}
#include <cstdio>
#include <cstdarg>
-static unsigned _debug_level = 2;
+static unsigned _debug_level = 1;
void set_debug_level(unsigned level)
{
#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"
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; }
{
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 },
};
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;
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();
}
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;
}
#include <l4/re/error_helper>
#include <l4/cxx/ipc_server>
-#include <l4/cxx/iostream>
-#include <l4/cxx/l4iostream>
#include "server.h"
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;
}
#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>
}
int
-System_bus::request_resource(L4::Ipc_iostream &ios)
+System_bus::request_resource(L4::Ipc::Iostream &ios)
{
l4vbus_resource_t res;
ios.get(res);
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;
}
}
int
-System_bus::request_iomem(L4::Ipc_iostream &ios)
+System_bus::request_iomem(L4::Ipc::Iostream &ios)
{
L4::Opcode op;
ios >> op;
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;
}
}
};
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;
}
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)
{
~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;
};
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;
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)
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();
}
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)
{
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;
};
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;
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);
}
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;
}
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;
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;
}
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;
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);
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);
}
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; }
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; }
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; }
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; }
{
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() {}
}
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;
}
int
-VPci_root::irq_enable(L4::Ipc_iostream &ios)
+VPci_root::irq_enable(L4::Ipc::Iostream &ios)
{
#if 0
l4_uint32_t bus;
}
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;
}
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)
{
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() {}
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; }
};
}
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;
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;
}
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;
}
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)
{
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));
}
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));
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));
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));
}
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))
#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>
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);
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:
}
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;
}
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;
}
long
-Vc::puts(L4::Ipc_iostream &ios)
+Vc::puts(L4::Ipc::Iostream &ios)
{
char buf[150];
char *s = 0;
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);
}
long
-Vc::puts_scale(L4::Ipc_iostream &ios)
+Vc::puts_scale(L4::Ipc::Iostream &ios)
{
char buf[150];
char *s = 0;
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);
}
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;
}
long
-Vc::vc_dispatch(L4::Ipc_iostream &ios)
+Vc::vc_dispatch(L4::Ipc::Iostream &ios)
{
l4_msgtag_t tag;
ios >> tag;
}
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;
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;
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;
}
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
#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 {
{
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;
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))
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))
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));
}
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))
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));
}
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));
}
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));
}
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));
}
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);
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())
{
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);
}
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);
}
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);
}
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))
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));
}
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;
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))
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))
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)
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)
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));
}
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));
}
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)
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)
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)
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));
}
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))
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));
}
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)
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));
}
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));
}
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))
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));
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));
}
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));
* \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
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; }
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;
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;
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)
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)
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(); }
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;
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;
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); }
}}
// 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;
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);
};
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;
*
* \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();
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;
*
* \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.
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;
#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
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);
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;
}
}
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;
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 << ", "
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;
* 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>
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
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;
}
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);
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;
}
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
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;
-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
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
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();
}
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;
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);
};
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;
}
};
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;
}
template<typename T>
inline
-T extract(L4::Ipc_istream &s)
+T extract(L4::Ipc::Istream &s)
{ T t; s >> t; return t; }
void
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
};
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); }
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);
};
#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__
{ 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.
/**
* \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.
*/
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
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
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
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;
# 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 */
# 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 */
# 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 */
* 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
EXTERN_C_BEGIN
-/**
+/**
* \defgroup l4util_random Random number support
* \ingroup l4util_api
*/
/**
* \brief Deliver next random number
* \ingroup l4util_random
- *
+ *
* \return A new random number
*/
L4_CV l4_uint32_t
/**
* \brief Initialize random number generator
* \ingroup l4util_random
- *
+ *
* \param seed Value to initialize
*/
L4_CV void
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);
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);
outstring("\r\n");
}
-void
+L4_CV void
apic_show_registers(void)
{
if (!apic_map_base)
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)
}
divval >>= 1;
}
-
+
if (div != -1)
{
apic_timer_divisor = newdiv;
}
-int
+L4_CV int
apic_check_working(void)
{
#define CLOCK_TICK_RATE 1193180 /* i8254 ticks per second */
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;
}
/* 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;
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);
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);
/*
* 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);
/* 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),
* 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;
return 0;
}
-l4_uint32_t
+L4_CV l4_uint32_t
l4_get_hz (void)
{
if (!l4_scaler_tsc_to_ns)
* 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);
}
* 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);
}
/*!\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){
* \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),
* \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),
* \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)){
* \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;
}
// 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;
*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;
#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);
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);
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);
*/
static char buffer[500];
-int l4_kprintf(const char *fmt, ...)
+L4_CV int l4_kprintf(const char *fmt, ...)
{
va_list list;
int err;
__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;
assert(*c != block);
*c = (l4la_free_t*)block;
assert(*c != next);
-
+
(*c)->next = next;
(*c)->size = 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;
return ret;
}
-l4_size_t
+L4_CV l4_size_t
l4la_avail(l4la_free_t **first)
{
__sanity_check_list(first, __FUNCTION__, "entry");
return a;
}
-void
+L4_CV void
l4la_dump(l4la_free_t **first)
{
printf("List_alloc [first=%p]\n", *first);
printf(" BUG: loop detected\n");
}
-void
+L4_CV void
l4la_init(l4la_free_t **first)
{
*first = 0;
#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;
#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;
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;
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;
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;
#include <l4/sys/kdebug.h>
#include <l4/util/reboot.h>
-void
+L4_CV void
l4util_reboot(void)
{
enter_kdebug("*#^"); /* Always available */
#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;
}
-void l4_usleep(int us)
+L4_CV void l4_usleep(int us)
{
l4_msgtag_t tag;
l4_timeout_t to;
* function implementations
*/
-slmap_t*
+L4_CV slmap_t*
map_new_entry(void* key, unsigned key_size, void* data)
{
slmap_t* map;
return map;
}
-slmap_t*
+L4_CV slmap_t*
map_new_sentry(char *key, void* data)
{
if (!key)
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;
return ret;
}
-slmap_t*
+L4_CV slmap_t*
map_remove(slmap_t* list, slmap_t* entry)
{
slmap_t* ret = list;
return ret;
}
-void
+L4_CV void
map_free_entry(slmap_t **entry)
{
if (*entry)
}
}
-slmap_t*
+L4_CV slmap_t*
map_get_at(slmap_t* list, int n)
{
int i=0;
return list;
}
-slmap_t*
+L4_CV slmap_t*
map_add(slmap_t* list, slmap_t* entry)
{
if (!entry)
return entry;
}
-void
+L4_CV void
map_insert_after(slmap_t* after, slmap_t* new_entry)
{
if (!new_entry)
after->next = new_entry;
}
-slmap_t*
+L4_CV slmap_t*
map_find(slmap_t* list, void* key, unsigned key_size)
{
while (list)
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));
}
-
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);
};
}
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;
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;
_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());
* \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,
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);
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);
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,
}
-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,
}
-gfxbitmap_font_t
+L4_CV gfxbitmap_font_t
gfxbitmap_font_get(const char *name)
{
unsigned i = 0;
}
/** Init lib */
-int
+L4_CV int
gfxbitmap_font_init(void)
{
unsigned chars;
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()
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:
{
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>();
}
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>();
}
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())
}
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;
}
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())
}
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())
}
};
-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;
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;
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;
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);
}
The dist/ directory contains the unmodified contents of
-libpng-1.5.1.tar.gz.
+libpng-1.5.2.tar.gz.
#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"
#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
/* #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 */
/* 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 */
/* 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 */
-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.
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
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
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]
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
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
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.
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
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})
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)
# 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)
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
Glenn Randers-Pehrson
glennrp at users.sourceforge.net
-March 31, 2011
+July 7, 2011
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@
# 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 $@
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@
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
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 $@
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:
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)
# 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
-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.
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.
#! /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>.
#
# 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=''
# 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]...
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
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.
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 $@
# Define the identity of the package.
PACKAGE='libpng'
- VERSION='1.5.2'
+ VERSION='1.5.4'
cat >>confdefs.h <<_ACEOF
-PNGLIB_VERSION=1.5.2
+PNGLIB_VERSION=1.5.4
PNGLIB_MAJOR=1
PNGLIB_MINOR=5
-PNGLIB_RELEASE=2
+PNGLIB_RELEASE=4
# 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
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\\"
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
#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
* 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).
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
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
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
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);
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
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().
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);
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);
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
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
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:
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
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.).
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.
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
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
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().
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
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);
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):
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:
#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);
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
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):
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
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
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
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
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
-.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
\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
\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
\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
.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
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
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
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);
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
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().
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);
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);
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
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
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:
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
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.).
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.
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
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
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().
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
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);
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):
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:
#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);
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
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):
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
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
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
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
.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
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
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).
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
Glenn Randers-Pehrson
glennrp at users.sourceforge.net
-March 31, 2011
+July 7, 2011
.\" end of man page
-.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"
\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)
-.TH PNG 5 "March 31, 2011"
+.TH PNG 5 "July 7, 2011"
.SH NAME
png \- Portable Network Graphics (PNG) format
.SH DESCRIPTION
/* 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.)
#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
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))
/* 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
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 */
#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.";
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 ||
"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;
}
# 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)
}
# 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
/* 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,
{
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;
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).
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 */
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 */
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 */
if (fp < 0)
{
fp = -fp;
- *ascii++ = 45; /* '-' PLUS 1 TOTAL 1*/
+ *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */
--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 */
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)
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;
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.
*/
* 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
/* 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] =
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,
#endif
};
-static png_int_32
+PNG_STATIC png_int_32
png_log8bit(unsigned int x)
{
unsigned int lg2 = 0;
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:
*
*
* 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:
* 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;
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;
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
# 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
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
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.
*/
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);
}
}
/* 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,
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).
*
(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))
{
(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++)
/* '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);
}
}
-/* 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.
*/
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));
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
{
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]
*
*
* 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)
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
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,
#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));
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 */
/* 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.)
* 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.
/* 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
* 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.
*/
/* 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;
*/
#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 */
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
* 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));
#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 */
#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
#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));
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));
#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));
# 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
*/
#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
#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
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,
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));
/* 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.
* scripts/symbols.def as well.
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(221);
+ PNG_EXPORT_LAST_ORDINAL(229);
#endif
#ifdef __cplusplus
/* 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
/* 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.)
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,
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
{
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 */
return NULL;
png_ptr->longjmp_fn = longjmp_fn;
- return &png_ptr->png_jmpbuf;
+ return &png_ptr->longjmp_buffer;
}
#endif
{
#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;
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);
{
# 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
/* 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,
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
}
* 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
/* 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.)
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)
{
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++;
{
# 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");
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 */
{
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
{
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
{
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
* (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.
*/
# 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)
# 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
*/
/* 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
#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
#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 */
#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
/* 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)
#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
* 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);
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));
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,
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
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
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
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,
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.
*/
#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.)
#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
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));
/* 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.)
#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
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 */
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)
{
"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
#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 */
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;
#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
* 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;
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
}
/* -------------- 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);
#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
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
/* 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.)
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
# 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)
{
return;
png_ptr->transformations |= PNG_16_TO_8;
- png_ptr->transformations &= ~PNG_EXPAND_16;
}
#endif
}
#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
#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(>est, 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)
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;
}
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 */
#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
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
}
#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;
+ }
+ }
}
}
}
#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(>est, 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)
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;
}
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);
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 &&
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;
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];
/* 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;
}
}
- /* 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;
}
}
#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
{
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
}
#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)
}
#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;
#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)
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;
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)
}
#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
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
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);
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,
png_ptr->row_info.width);
}
#endif
-
}
#ifdef PNG_READ_PACK_SUPPORTED
}
#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;
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)
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)
{
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)
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
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)
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
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)
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];
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;
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
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);
}
}
}
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
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;
}
}
}
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
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);
}
}
}
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
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;
}
}
}
#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);
}
}
}
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));
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
}
}
}
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
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;
}
}
}
#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);
}
}
}
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)));
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);
}
}
}
#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;
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);
}
}
}
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
* 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;
}
#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.
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;
*/
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;
{
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)
{
row_info->rowbytes = row_width;
}
- if (trans_value != NULL)
+ if (trans_color != NULL)
{
if (row_info->bit_depth == 8)
{
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++)
}
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++)
}
}
#endif /* PNG_READ_QUANTIZE_SUPPORTED */
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
#ifdef PNG_MNG_FEATURES_SUPPORTED
/* Undoes intrapixel differencing */
/* 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.)
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)
* 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.
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.
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. */
}
*newlength = prefix_size;
}
-#endif
+#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
/* Read and check the IDHR chunk */
void /* PRIVATE */
{
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;
}
}
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);
}
{
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 */
/* 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;
}
{
png_size_t truelen;
png_byte buf[6];
+ png_color_16 background;
png_debug(1, "in png_handle_bKGD");
*/
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)
{
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
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);
/* 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],
{
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,
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)
{
/* 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.)
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
{
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;
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
* (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 */
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 */
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 */
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 */
#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 */
/* 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.)
* 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. */
int bit_depth, color_type;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
- jmp_buf png_jmpbuf;
+ jmp_buf tmp_jmpbuf;
#endif
#endif
#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
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
}
#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
# 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
}
/* 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;
/* 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.)
/* 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)
{
{
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 */
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)
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)
/* 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
*
* transformations performed by libpng.
*/
+#define _POSIX_SOURCE 1
+
#include "png.h"
#if PNG_LIBPNG_VER < 10500
/* This delibarately lacks the PNG_CONST. */
#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 */
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)
{
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)
/* 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, " ");
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));
}
# 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 */
}
}
+#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)
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. */
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
#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... */
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
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 */
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_bytep mark)
{
- /* 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
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
{
store_freebuffer(&ps->new);
ps->writepos = 0;
+ if (ps->palette != NULL)
+ {
+ free(ps->palette);
+ ps->palette = NULL;
+ ps->npalette = 0;
+ }
}
static void
store_freebuffer(&(*ppf)->data);
(*ppf)->datacount = 0;
+ if ((*ppf)->palette != NULL)
+ {
+ free((*ppf)->palette);
+ (*ppf)->palette = NULL;
+ (*ppf)->npalette = 0;
+ }
free(*ppf);
*ppf = NULL;
}
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;
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)
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. */
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)
{
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)
return 0;
}
+#endif
static int
store_read_buffer_next(png_store *ps)
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
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 ************************/
*/
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;
double error_gray_16;
double error_color_8;
double error_color_16;
+ double error_indexed;
/* Flags: */
/* Whether or not to interlace. */
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 */
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.
*/
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;
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;
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
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. */
* 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
{
switch (colour_type)
{
+ default: png_error(pp, "invalid color type");
+
case 0: return bit_depth;
case 2: return 3*bit_depth;
case 4: return 2*bit_depth;
case 6: return 4*bit_depth;
-
- default: png_error(pp, "invalid color type");
}
}
#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)
case 48:
case 64:
return 2048;/* 4 x 65536 pixels. */
+# define TRANSFORM_HEIGHTMAX 2048
default:
return 0; /* Error, will be caught later */
*/
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);
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);
}
}
+#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);
}
}
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;
{
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.
*/
}
}
-/* 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
/* 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);
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);
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)
* 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)
{
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 },
};
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
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)
{
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");
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
* 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) */
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;
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: */
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;
* 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.
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;
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
*/
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);
}
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)
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)
{
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);
}
}
}
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];
* 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);
* 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);
}
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;
/* 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. */
"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)
{
* 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);
}
}
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))
* 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))
* 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))
/******************************* 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
*/
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);
}
/* 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).
*/
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)
{
/* 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: */
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;
}
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 ==
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. */
*/
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 */
{
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. */
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) */
/* 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);
/* 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*/\
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
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,
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);
}
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,
{
/* 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);
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,
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,
{
/* 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;
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'
*/
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,
* 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);
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,
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;
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,
that->have_tRNS = 0;
that->alphaf = 1;
- that->alphae = 0;
this->next->mod(this->next, that, pp, display);
}
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)
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 +
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,
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);
/* 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;
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);
#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)
/* 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];
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
{
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;
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*/);
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;
* 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: */
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];
}
} /* row (y) loop */
- dp->maxerrout = maxerrout;
- dp->maxerrabs = maxerrabs;
- dp->maxerrpc = maxerrpc;
dp->this.ps->validated = 1;
}
{
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.
*/
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
{
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)
/* 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. */
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)
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
{
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)
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);
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;
}
}
-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
}
}
}
}
/* 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
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;
}
#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);
/* 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)
{
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)
{
}
}
#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
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;
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;
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
*/
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
/* 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)
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;
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)
{
pm.test_transform = 1;
transform_enable(*argv + sizeof "--transform-enable");
}
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
else if (strcmp(*argv, "--gamma") == 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 (strcmp(*argv, "--nogamma") == 0)
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]);
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
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
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)
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
if (pm.test_standard)
{
perform_interlace_macro_validation();
+ perform_formatting_test(&pm.this);
perform_standard_test(&pm);
perform_error_test(&pm);
}
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)
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",
/* 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.)
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)))
{
{
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)))
{
{
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)))
{
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");
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
#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;
}
#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
{
/* 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);
/* 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);
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;
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);
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);
#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;
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
}
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)
{
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)
{
#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);
/* 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.)
#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
/* Transform the data according to the user's wishes. The order of
* transformations is significant.
*/
#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
}
}
#endif
+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
#ifdef PNG_MNG_FEATURES_SUPPORTED
/* Undoes intrapixel differencing */
/* 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.)
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
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,
* 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;
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++)
{
(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
int interlace_type)
{
PNG_IHDR;
- int ret;
png_byte buf[13]; /* Buffer to store the IHDR info */
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
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.
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)
{
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 */
(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);
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 = ' ';
}
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 */
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;
}
png_ptr->zstream.avail_out);
}
- deflateReset(&png_ptr->zstream);
+ png_zlib_release(png_ptr);
png_ptr->zstream.data_type = Z_BINARY;
}
* 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)
/* 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;
{
/* 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);
-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
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
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)
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
# Modeled after libxml-config.
-version=1.5.2
+version=1.5.4
prefix=""
libdir=""
libs=""
Name: libpng
Description: Loads and saves PNG files
-Version: 1.5.2
+Version: 1.5.4
Libs: -L${libdir} -lpng15
Cflags: -I${includedir}
VERMAJ = 1
VERMIN = 5
-VERMIC = 2
+VERMIC = 4
VER = $(VERMAJ).$(VERMIN).$(VERMIC)
NAME = libpng
PACKAGE = $(NAME)-$(VER)
# Library name:
LIBNAME = libpng15
PNGMAJ = 15
-RELEASE = 2
+RELEASE = 4
# Shared library names:
LIBSO=$(LIBNAME).so
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
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
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 \
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
# 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 = ""
#
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
# 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
#
# 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
#
# 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
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
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
# 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
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
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
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
chunk gAMA
chunk hIST
chunk iCCP
-chunk iTXt requires TEXT
+chunk iTXt
chunk oFFs
chunk pCAL
chunk sCAL
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
# 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.
/* 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 */
/* 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 */
#!/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'
LIBRARY
EXPORTS
-;Version 1.5.2
+;Version 1.5.4
png_access_version_number @1
png_set_sig_bytes @2
png_sig_cmp @3
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
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
* -#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)
{
* -#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();
#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);
* -#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)
{
*
* \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)
/*
* \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);
* -#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)
{
* -#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);
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
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;
}
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));
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)
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)
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)
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;
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;
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));
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));
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));
}
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;
}
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));
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));
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));
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));
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));
*
* \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(),
LDFLAGS +=
#CPPFLAGS += -fPIC
-REQUIRES_LIBS := libloader libkproxy
+REQUIRES_LIBS := libloader libkproxy cxx_libc_io cxx_io
include $(L4DIR)/mk/prog.mk
};
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;
}
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;
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();
};
#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;
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; }
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;
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])
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() {}
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;
}
};
}
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())
{
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];
~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);
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;
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;
}
template<typename T>
inline
-T extract(L4::Ipc_istream &s)
+T extract(L4::Ipc::Istream &s)
{ T t; s >> t; return t; }
void
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>();
};
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;
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);
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);
};
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;
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);
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
#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;
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;
}
-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;
}
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;
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;
};
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;
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) {}
//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();
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();
};
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(); }
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);
};
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;
}
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;
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;
}
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;
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
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;
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)
}
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;
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;
};
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;
{};
int
-Allocator::dispatch(l4_umword_t obj, L4::Ipc_iostream &ios)
+Allocator::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios)
{
L4::Opcode op;
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();
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;
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; }
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);
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;
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 << ", "
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;
{ 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;
}
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;
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])
{
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() {}
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;
}
};
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;
}
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);
{
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];
~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);
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);
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;
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)
};
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;
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*/)
{}
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() {}
};
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;
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);
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); }
};
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
#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;
//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(); }
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()))
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);
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
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()))
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()))
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))
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;
#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>
#include <l4/scout-gfx/redraw_manager>
#include "browser_window.h"
+#include <iostream>
+#include <l4/cxx/std_exc_io>
using Scout_gfx::Document;
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;
}
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/$@)
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;
}
};
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;
}
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;
-# 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
* 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)
* 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 };
* \return pointer to object, NULL if allocation failed.
*/
/*****************************************************************************/
-void *
+L4_CV void *
l4slab_alloc(l4slab_cache_t * cache)
{
int ret;
* \param objp Pointer to object
*/
/*****************************************************************************/
-void
+L4_CV void
l4slab_free(l4slab_cache_t * cache, void * objp)
{
l4slab_slab_t * slab;
* Add the slab to the slab cache.
*/
/*****************************************************************************/
-void
+L4_CV void
l4slab_add_slab(l4slab_cache_t * cache, void * buffer, void * data)
{
/* sanity checks */
* \param data Application data pointer
*/
/*****************************************************************************/
-void
+L4_CV void
l4slab_set_data(l4slab_cache_t * cache, void * data)
{
if (cache == NULL)
* data pointer set.
*/
/*****************************************************************************/
-void *
+L4_CV void *
l4slab_get_data(l4slab_cache_t * cache)
{
if (cache == NULL)
* \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 };
* \param cache Cache descriptor
*/
/*****************************************************************************/
-void
+L4_CV void
l4slab_dump_cache_free(l4slab_cache_t * cache)
{
l4slab_slab_t * slab;
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
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;
}
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;
{
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;
}
}
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;
{
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);
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);
};
}
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;
return -L4_EBADPROTO;
}
-
switch (L4::Ipc::read<L4::Factory::Proto>(ios))
{
case L4Re::Namespace::Protocol:
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);
The contrib directory contains the unmodified contents of
-sqlite-autoconf-3070602.tar.gz
+sqlite-autoconf-3070701.tar.gz
-# 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
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
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@
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@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
+builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
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
@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 \
$(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:
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)
@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 $@ $<
-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)
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)
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
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) \
&& 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 \
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
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"
html: html-am
+html-am:
+
info: info-am
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
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:
#! /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
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
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
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\\(.*\\)"`;;
}
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
;;
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='> '
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
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\(//\)$' \| \
}
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'"
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,
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.
# 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
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
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
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
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
| --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 ;;
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
[\\/$]* | ?:[\\/]* ) 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'
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.
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
# 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]...
--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 $@
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
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
-* ) 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
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
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.
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"
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";;
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
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=: ;;
,);;
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
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'
# 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,
# 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
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.
;;
esac
-done
+ done
IFS=$as_save_IFS
rm -rf conftest.one conftest.two conftest.dir
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}.
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
# 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
# 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"
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
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
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
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
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
# 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
# Define the identity of the package.
PACKAGE='sqlite'
- VERSION='3.7.6.2'
+ VERSION='3.7.7.1'
cat >>confdefs.h <<_ACEOF
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
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
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
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
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
.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=
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
# 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:
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,
# 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
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
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
}
_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
$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
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
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
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
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
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
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>
-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
# 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'
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
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
# 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
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.
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
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.
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>
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) ;;
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.
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>
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) ;;
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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>
-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
# 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'
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
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
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
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
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
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
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
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 ;;
# 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 ;;
# 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 ;;
# 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='-'
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='-'
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.
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
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
$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"
$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
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
$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"
$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
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
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*)
;;
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.
;;
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
;;
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
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'
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
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
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"
;;
*-*-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*)
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
# 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
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
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'
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
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
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
# <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>
#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
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
# <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>
#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
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>
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
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
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>
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
# <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>
#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
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
# <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>
#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
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
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
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
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
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
# 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
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
# 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
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"
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"
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
# 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
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
-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.
$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
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
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; }
#
#
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
-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.
$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
# 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
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
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
-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
$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*
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
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=
# -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
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"
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
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"
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
# 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
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
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
;;
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'
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
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" || \
# 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
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
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.
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.
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.
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.
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.
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
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 :
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
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
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 :
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
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
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
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
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"
# 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
# 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.
# 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
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*)
;;
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.
;;
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
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
# -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
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"
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
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"
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
};
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.
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.
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; }
#
#
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
-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.
$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
# 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
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
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
-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
$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*
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
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'
;;
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
# 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
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
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
;;
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'
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
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" || \
# 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
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
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"
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
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; }
#
#
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
-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.
$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
# 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
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
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
-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
$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*
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
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=
# -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"
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"
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
# 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
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
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
;;
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'
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
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" || \
# 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
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
-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.
$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
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
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; }
#
#
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
-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.
$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
# 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
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
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
-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
$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*
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
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=
# -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
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"
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
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"
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
# 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
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
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
;;
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'
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
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" || \
# 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
;;
*)
- { { $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
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
-{ $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
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
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
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
# 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 ();
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
# --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.
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.
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
# --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.
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.
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
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
(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 quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
sed -n \
"s/'/'\\\\''/g;
s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
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
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
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.
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
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
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
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\\(.*\\)"`;;
}
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
;;
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='> '
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
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\(//\)$' \| \
}
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
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
'
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
_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"
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:
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."
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 )
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
"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
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.
{
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.
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
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
t delim
:nl
h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
t more1
s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
p
t nl
:delim
h
-s/\(.\{148\}\).*/\1/
+s/\(.\{148\}\)..*/\1/
t more2
s/["\\]/\\&/g; s/^/"/; s/$/"/
p
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),
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
[\\/$]*) 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
`' 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.
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
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
# 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
/@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
s&@infodir@&$infodir&g
s&@localedir@&$localedir&g
s&@mandir@&$mandir&g
- s&\\\${datarootdir}&$datarootdir&g' ;;
+ s&\\\${datarootdir}&$datarootdir&g' ;;
esac
_ACEOF
$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;}
-) 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
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
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.
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
#
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.
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) );
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," ...> ");
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);
}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;
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 ){
/******************************************************************************
** 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
** [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
** 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.
**
** 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 */
#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() */
#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 */
/*
** 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().
**
** 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
** 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.
** 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]
** 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
** 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].
/*
** 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.
** 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
** [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.
** [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
** [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
** 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.)^
** 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
** 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
** 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
** 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].
** 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
** [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]
** [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
** 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
** 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 */
#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
**
** ^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
** 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 */
/*
** 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
** 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>
** </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
** [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
** 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
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
**
** 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>
*/
** ^[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.
**
** 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
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);
};
/*
**
** ^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
#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
** 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
/*
** 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
** 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]
** [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
** 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
** 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>
** 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
/*
** 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.
** 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
** 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
** 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.)^
** [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.)^
** 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
** ^(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
/*
** 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
** 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()
** 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.
** ^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
** ^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
** 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
** 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.
** 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
** 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*]
** 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
** 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.
** 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
** 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
#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
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;
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 */
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);
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*);
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*));
** 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 */
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. */
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) */
#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() */
#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 */
/*
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) */
};
** 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[] */
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 */
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 */
};
/*
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);
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
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);
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);
# 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 **);
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*);
};
#endif
-
+#ifndef SQLITE_USE_URI
+# define SQLITE_USE_URI 0
+#endif
/*
** The following singleton contains the global configuration for
SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */
1, /* bCoreMutex */
SQLITE_THREADSAFE==1, /* bFullMutex */
+ SQLITE_USE_URI, /* bOpenUri */
0x7ffffffe, /* mxStrlen */
100, /* szLookaside */
500, /* nLookaside */
0, /* nRefInitMutex */
0, /* xLog */
0, /* pLogArg */
+ 0, /* bLocaltimeFault */
};
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 */
#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.
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 ){
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 */
** 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;
*/
if( strcmp(z, "localtime")==0 ){
computeJD(p);
- p->iJD += localtimeOffset(p);
+ p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p);
- rc = 0;
}
break;
}
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;
}
}
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;
}
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{
** 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 */
}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) );
|| (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 */
){
-#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));
#endif
return (u8)(h & 0xf);
}
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
/*
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;
}
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 ********************************************/
/*
# include <sys/mount.h>
#endif
+#ifdef HAVE_UTIME
+# include <utime.h>
+#endif
+
/*
** Allowed values of unixFile.fsFlags
*/
#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
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)
{ "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 },
{ "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 },
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
*/
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;
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{
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 */
(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;
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.
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{
}else{
*pp = 0;
}
+ if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
** 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 */
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 */
**
** "<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';
}
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
- }else{
- *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
}
return rc;
}
#endif
};
+
/*
** Forward prototypes.
*/
** 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;
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.
pFile->hMutex = CreateMutexW(NULL, FALSE, zName);
if (!pFile->hMutex){
pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename);
free(zName);
return FALSE;
}
/* 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;
}
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;
}
#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);
}
/*
}
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 */
}
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;
}
/* 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"));
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
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
}
&& ((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;
}
if( res == 0 ){
pFile->lastErrno = GetLastError();
+ /* No need to log a failure to lock */
}
return res;
}
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;
}
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 ){
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.
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 ){
*/
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;
}
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;
}
}
}
if( !pMap ){
pShmNode->lastErrno = GetLastError();
- rc = SQLITE_IOERR;
+ rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath);
if( hMap ) CloseHandle(hMap);
goto shmpage_out;
}
*/
#if SQLITE_OS_WINCE==0
}else{
- zConverted = utf8ToMbcs(zFilename);
+ zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
#endif
}
/* caller will handle out of memory */
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.
*/
if( h==INVALID_HANDLE_VALUE ){
pFile->lastErrno = GetLastError();
+ winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name);
free(zConverted);
if( isReadWrite ){
return winOpen(pVfs, zName, id,
"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);
}
/*
}
}else{
if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
+ winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename);
free(zConverted);
return SQLITE_IOERR_ACCESS;
}else{
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
}
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;
pGroup = (PGroup*)&pCache[1];
pGroup->mxPinned = 10;
}else{
- pGroup = &pcache1_g.grp;
+ pGroup = &pcache1.grp;
}
pCache->pGroup = pGroup;
pCache->szPage = szPage;
#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)
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
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
** 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 ){
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
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 */
/* 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);
}
}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);
}
SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){
if( iLimit>=-1 ){
pPager->journalSizeLimit = iLimit;
+ sqlite3WalLimit(pPager->pWal, iLimit);
}
return pPager->journalSizeLimit;
}
*/
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
);
}
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 */
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 */
#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.
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;
+ }
}
}
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 */
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);
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 ){
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
** 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
}
/* 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 ){
}
}
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));
*/
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]));
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 ){
*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 ){
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]);
*/
#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
** 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 */
#endif
assert( db!=0 );
+ assert( pVfs!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( (flags&0xff)==flags ); /* flags fit in 8 bits */
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;
}
assert( pCur->apPage[0]->intKey || pIdxKey );
for(;;){
- int lwr, upr;
+ int lwr, upr, idx;
Pgno chldPg;
MemPage *pPage = pCur->apPage[pCur->iPage];
int c;
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 ){
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 );
** "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 */
*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);
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);
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);
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);
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;
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]);
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.
*/
}
/*
-** 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
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);
}
/*
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 ){
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. */
** 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;
*/
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);
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);
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++;
** This routine destroys a UnpackedRecord object.
*/
SQLITE_PRIVATE void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
+#ifdef SQLITE_DEBUG
int i;
Mem *pMem;
*/
if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem);
}
+#endif
if( p->flags & UNPACKED_NEED_FREE ){
sqlite3DbFree(p->pKeyInfo->db, p);
}
/* 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.
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);
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,
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;
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.
*/
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];
}
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;
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 */
} cm;
struct OP_Trace_stack_vars {
char *zTrace;
+ char *z;
} cn;
} u;
/* End automatically generated code
/* 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.
*/
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
#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;
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.
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));
** 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
** 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
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
** 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.
/* 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.
*/
}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 ){
}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;
+ }
}
}
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,
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);
/* 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.
** 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.
*/
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;
}
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;
/* 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.
**
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;
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++){
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;
}
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
** release the mutexes on btrees that were acquired at the
** top. */
vdbe_return:
+ db->lastRowid = lastRowid;
sqlite3VdbeLeave(p);
return rc;
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);
}
}
/* 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);
}
}
}
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;
}
/* 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
}
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);
** 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;
/* 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{
#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));
}
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);
}
}
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");
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
}
}
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;
** 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 };
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;
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;
sqlite3_value **argv
){
const unsigned char *zA, *zB;
- int escape = 0;
+ u32 escape = 0;
int nPat;
sqlite3 *db = sqlite3_context_db_handle(context);
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
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 ),
/* 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);
}
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
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:
**
** 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
/*
** 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.
*/
mask &= ~(SQLITE_ForeignKeys);
}
- if( getBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight) ){
db->flags |= mask;
}else{
db->flags &= ~mask;
int b = -1;
assert( pBt!=0 );
if( zRight ){
- b = getBoolean(zRight);
+ b = sqlite3GetBoolean(zRight);
}
if( pId2->n==0 && b>=0 ){
int ii;
#ifndef NDEBUG
if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
if( zRight ){
- if( getBoolean(zRight) ){
+ if( sqlite3GetBoolean(zRight) ){
sqlite3ParserTrace(stderr, "parser: ");
}else{
sqlite3ParserTrace(0, 0);
*/
if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
if( zRight ){
- sqlite3RegisterLikeFunctions(db, getBoolean(zRight));
+ sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
}
}else
** 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;
}
}
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 ){
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 */
}
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
- if( chngRowid ){
+ if( hasFK || chngRowid ){
reg = ++pParse->nMem;
}else{
reg = 0;
/* 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;
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 */
}
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);
*/
#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
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);
}
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);
}
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;
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 ){
** 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);
}
sqlite3DbFree(db, zModuleName);
- db->pVTab = 0;
return rc;
}
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 */
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;
}
/*
/* 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;
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;
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);
x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset);
if( x ) x(p);
}
+ pVTab->iSavepoint = 0;
sqlite3VtabUnlock(pVTab);
}
sqlite3DbFree(db, db->aVTrans);
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 ){
}
}
- /* 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;
}
}
+/*
+** 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 ************************************************/
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 */
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 ){
}
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;
break;
}
+ case SQLITE_CONFIG_URI: {
+ sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
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"
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
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;
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.
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 ){
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);
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
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 ******************************************/
/*
** 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 *****************************************/
/*
******************************************************************************
**
*/
-
#ifndef _FTSINT_H
#define _FTSINT_H
# 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 **********************************/
/*
*/
#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.
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
/* 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;
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
};
/*
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 */
#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 */
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;
};
/*
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 **);
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
int flags;
};
-struct Fts3SegReaderCursor {
+struct Fts3MultiSegReader {
/* Used internally by sqlite3Fts3SegReaderXXX() calls */
Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */
int nSegment; /* Size of apSegment array */
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 */
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 *);
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
}
/*
-** 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;
}
/*
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++){
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 );
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.
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)
/* 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. */
}
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 */
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;
/* 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';
}
/* 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);
pTokenizer->pModule->xDestroy(pTokenizer);
}
}else{
+ assert( p->pSegments==0 );
*ppVTab = &p->base;
}
return rc;
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;
}
sqlite3Fts3FreeDeferredTokens(pCsr);
sqlite3_free(pCsr->aDoclist);
sqlite3_free(pCsr->aMatchinfo);
+ assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
sqlite3_free(pCsr);
return SQLITE_OK;
}
*/
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{
** 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 ){
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
if( zCsr>zEnd ){
- return SQLITE_CORRUPT;
+ return SQLITE_CORRUPT_VTAB;
}
while( zCsr<zEnd && (piFirst || piLast) ){
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 ){
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);
}
}
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);
}
/*
-** 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 */
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
** 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;
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;
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] ){
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);
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 ){
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);
}
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 */
}
if( rc==SQLITE_OK ){
- rc = fts3TermSelectMerge(&tsc);
+ rc = fts3TermSelectMerge(p, &tsc);
}
if( rc==SQLITE_OK ){
*ppOut = tsc.aaOutput[0];
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
** 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;
}
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;
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]);
);
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;
}
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;
** 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);
}
*/
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;
}
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;
/* 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;
}
** 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;
}
** 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;
}
** 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;
}
/*
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,
/* xRollback */ fts3RollbackMethod,
/* xFindFunction */ fts3FindFunctionMethod,
/* xRename */ fts3RenameMethod,
+ /* xSavepoint */ fts3SavepointMethod,
+ /* xRelease */ fts3ReleaseMethod,
+ /* xRollbackTo */ fts3RollbackToMethod,
};
/*
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;
}
#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 ************************************************/
******************************************************************************
**
*/
-
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
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 */
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);
int isScan;
UNUSED_PARAMETER(nVal);
+ UNUSED_PARAMETER(idxStr);
assert( idxStr==0 );
assert( idxNum==FTS4AUX_EQ_CONSTRAINT || idxNum==0
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 ){
0, /* xCommit */
0, /* xRollback */
0, /* xFindFunction */
- 0 /* xRename */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0 /* xRollbackTo */
};
int rc; /* Return code */
#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 */
};
iEnd++;
}
if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
- pRet->pPhrase->isNot = 1;
+ pParse->isNot = 1;
}
}
nConsumed = iEnd;
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;
}
}
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;
}
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.
*/
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));
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
*/
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);
}
}
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,
-
/*
** Class derived from sqlite3_tokenizer
*/
** * 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
){
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;
-
typedef struct simple_tokenizer {
sqlite3_tokenizer base;
char delim[128]; /* flag ASCII delimiters */
*/
#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;
**
** sqlite3Fts3SegReaderNew()
** sqlite3Fts3SegReaderFree()
-** sqlite3Fts3SegReaderCost()
** sqlite3Fts3SegReaderIterate()
**
** Methods used to manipulate Fts3SegReader structures:
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
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;
};
** 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) */
#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
#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,
/* 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 ?",
/* 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;
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;
** 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;
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
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;
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.
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
+ );
}
}
}
/*
-** 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;
}
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]);
}
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;
** 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.
** 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 */
/* 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);
}
** 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;
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 */
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 ){
}
*paBlob = aByte;
}
- *pnBlob = nByte;
}
return rc;
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 */
}
if( !pNext || pNext>=&pReader->aNode[pReader->nNode] ){
- int rc; /* Return code from Fts3ReadBlock() */
if( fts3SegReaderIsPending(pReader) ){
Fts3HashElem *pElem = *(pReader->ppNextElem);
if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode);
+ sqlite3_blob_close(pReader->pBlob);
+ pReader->pBlob = 0;
}
pReader->aNode = 0;
}
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 ){
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;
** 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;
}
** 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;
}
/*
** *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;
}
sqlite3_free(pReader->zTerm);
if( !fts3SegReaderIsRootOnly(pReader) ){
sqlite3_free(pReader->aNode);
+ sqlite3_blob_close(pReader->pBlob);
}
}
sqlite3_free(pReader);
/*
** 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)) ){
}
aElem = aElem2;
}
+
aElem[nElem++] = pE;
}
}
}
}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;
}
}
- if( isPrefix ){
+ if( bPrefix ){
sqlite3_free(aElem);
}
*ppReader = pReader;
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
** 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);
}
/*
-** 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);
}
*/
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 */
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;
}
*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
** 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;
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;
** 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);
}
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 */
** 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++;
}
}
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;
}
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);
}
}
- fts3SegReaderSort(apSegment, nMerge, j, fts3SegReaderDoclistCmp);
+ fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
pCsr->aDoclist = pCsr->aBuffer;
return rc;
}
+
SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
- Fts3SegReaderCursor *pCsr /* Cursor object */
+ Fts3MultiSegReader *pCsr /* Cursor object */
){
if( pCsr ){
int i;
** 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 ){
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:
/*
-** 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;
}
/*
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:
**
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]);
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.
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);
- }
}
/*
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;
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.
*/
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
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);
}
fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nChng);
}
+ update_out:
sqlite3_free(aSzIns);
sqlite3Fts3SegmentsClose(p);
return rc;
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);
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
*/
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;
}
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;
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.
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]
+ );
}
/*
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;
}
}
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;
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 */
};
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);
}
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{
case FTS3_MATCHINFO_NDOC:
if( bGlobal ){
- sqlite3_int64 nDoc;
+ sqlite3_int64 nDoc = 0;
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
pInfo->aMatchinfo[0] = (u32)nDoc;
}
};
struct TermOffsetCtx {
+ Fts3Cursor *pCsr;
int iCol; /* Column of table to populate aTerm for */
int iTerm;
sqlite3_int64 iDocid;
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);
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.
);
rc = fts3StringAppend(&res, aBuffer, -1);
}else if( rc==SQLITE_DONE ){
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_VTAB;
}
}
}
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;
}
}
if( pNode!=0 ){
nodeHashInsert(pRtree, pNode);
}else{
- rc = SQLITE_CORRUPT;
+ rc = SQLITE_CORRUPT_VTAB;
}
*ppNode = pNode;
}else{
return SQLITE_OK;
}
}
- return SQLITE_CORRUPT;
+ return SQLITE_CORRUPT_VTAB;
}
/*
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;
}
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;
}
o = 0.0;
break;
}else{
- o = o * (x2-x1);
+ o = o * (float)(x2-x1);
}
}
overlap += o;
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
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;
int iCell;
if( nodeParentIndex(pRtree, p, &iCell) ){
- return SQLITE_CORRUPT;
+ return SQLITE_CORRUPT_VTAB;
}
nodeGetCell(pRtree, pParent, iCell, &cell);
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));
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(
}
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;
static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
int rc;
int rc2;
- RtreeNode *pParent;
+ RtreeNode *pParent = 0;
int iCell;
assert( pNode->nRef==1 );
}
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]);
}
}
/* 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;
}
/*
-** 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) );
}
}
- /* 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;
}
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 */
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(
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 ){
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]);
**
*************************************************************************
** 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
** [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
** 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.
**
** 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 */
#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() */
#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 */
/*
** 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().
**
** 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
** 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.
** 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]
** 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
** 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].
/*
** 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.
** 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
** [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.
** [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
** [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
** 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.)^
** 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
** 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
** 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
** 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].
** 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
** [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]
** [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
** 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
** 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 */
#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
**
** ^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
** 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 */
/*
** 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
** 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>
** </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
** [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
** 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
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
**
** 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>
*/
** ^[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.
**
** 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
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);
};
/*
**
** ^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
#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
** 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
/*
** 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
** 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]
** [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
** 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
** 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>
** 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
/*
** 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.
** 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
** 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
** 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.)^
** [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.)^
** 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
** ^(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
/*
** 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
** 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()
** 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.
** ^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
** ^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
** 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
** 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.
** 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
** 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*]
** 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
** 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.
** 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
** 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
#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
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}
-Provides: libc libpthread
+Provides: libc libpthread libc_minimal_l4re
requires: l4sys l4re
Maintainer: adam@os.inf.tu-dresden.de
PKGDIR ?= ..
L4DIR ?= $(PKGDIR)/../..
-TARGET = uclibc libpthread
+TARGET = uclibc libpthread minimal_l4re
include $(L4DIR)/mk/subdir.mk
{
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;
}
--- /dev/null
+# 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
# 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)
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
--- /dev/null
+#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);
+}
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) \
$(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)
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;
}
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);
};
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);
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;
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",
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;
}
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;
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");
$unzip_tmp);
$cmdline =~ s/^\S+\s*//;
+ $cmdline =~ s/,/,,/g;
$fp.' '.$cmdline;
}
"-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");
-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"
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
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)
# 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
# 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
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
$(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
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
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)
# 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
# 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
$(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
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
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
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
# ---------------------------------------------------------------------------
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
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
.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
@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'
# Documentation targets
# ---------------------------------------------------------------------------
%docs: scripts_basic FORCE
+ $(Q)$(MAKE) $(build)=scripts build_docproc
$(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # 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' \
# 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
# 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
-kconfig taken from vanilla Linux 2.6.39, and slightly patched.
+kconfig taken from vanilla Linux 3.0, and slightly patched.
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))
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))
+
######
###
# 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,
# 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
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
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
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)" \
"$(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 \
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)
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)
#
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)
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))
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)
# ---------------------------------------------------------------------------
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
# .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
# 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 \
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
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
hostprogs-y += mconf
endif
+ifeq ($(MAKECMDGOALS),update-po-config)
+ hostprogs-y += kxgettext
+endif
+
ifeq ($(MAKECMDGOALS),xconfig)
qconf-target := 1
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
$(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
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;
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();
const char *str;
const char *name;
FILE *out, *tristate, *out_h;
- time_t now;
int i;
sym_clear_all_valid();
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);
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;
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);
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);
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();
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);
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)) {
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));
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;
{
struct buffer *parent;
- current_file->flags |= FILE_SCANNED;
- current_file->flags &= ~FILE_BUSY;
current_file = current_file->parent;
parent = current_buf->parent;
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 */
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);
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)
mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
switch (mb.exec()) {
case QMessageBox::Yes:
- conf_write(NULL);
+ saveConfig();
case QMessageBox::No:
e->accept();
break;
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));
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;
{
struct buffer *parent;
- current_file->flags |= FILE_SCANNED;
- current_file->flags &= ~FILE_BUSY;
current_file = current_file->parent;
parent = current_buf->parent;